Skip to content

[BUG] UFCS with variable template in scope fails #807

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

Open
JohelEGP opened this issue Nov 4, 2023 · 5 comments
Open

[BUG] UFCS with variable template in scope fails #807

JohelEGP opened this issue Nov 4, 2023 · 5 comments
Labels
bug Something isn't working

Comments

@JohelEGP
Copy link
Contributor

JohelEGP commented Nov 4, 2023

Title: UFCS with variable template in scope fails.

Description:

std::vector<int>().empty() will fail given using std::views::empty;.
That should end up calling the member empty of std::vector.
But the UFCS macro fails on the free function branch.

All compilers fail: https://compiler-explorer.com/z/bWejqfodq.
With #506, MSVC starts accepting: https://compiler-explorer.com/z/TYaMW7av6.

Minimal reproducer (https://cpp2.godbolt.org/z/7nfzr7zYx):

#include <ranges>
#include <vector>
using std::views::empty;
auto _ = std::vector<int>().empty();
main: () = {
  _ = std::vector<int>().empty();
}
Commands:
cppfront main.cpp2
clang++18 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -I . main.cpp

Expected result: A well-formed program that calls the member empty of std::vector.

Actual result and error:

Cpp2 lowered to Cpp1:
//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"



//=== Cpp2 type definitions and function declarations ===========================

#include <ranges>
#include <vector>
using std::views::empty;
auto _ = std::vector<int>().empty();
auto main() -> int;
  

//=== Cpp2 function definitions =================================================


auto main() -> int{
  static_cast<void>(CPP2_UFCS_0(empty, std::vector<int>()));
}
Output:
main.cpp2:6:33: error: use of variable template 'empty' requires template arguments
    6 |   static_cast<void>(CPP2_UFCS_0(empty, std::vector<int>()));
      |                                 ^
/opt/compiler-explorer/clang-trunk-20231104/bin/../include/c++/v1/__ranges/empty_view.h:45:36: note: template is declared here
   44 |   template <class _Tp>
      |   ~~~~~~~~~~~~~~~~~~~~
   45 |   inline constexpr empty_view<_Tp> empty{};
      |                                    ^
1 error generated.
@JohelEGP JohelEGP added the bug Something isn't working label Nov 4, 2023
@JohelEGP
Copy link
Contributor Author

JohelEGP commented Nov 5, 2023

I noticed the same failure if you attempt to call std::vector<int>().std::vector<int>::empty() (https://cpp2.godbolt.org/z/c5veMnjMe).
Branch main: https://compiler-explorer.com/z/9oa1Ga3Tx (but see #555).
#506: https://compiler-explorer.com/z/qvK7E4Kj8.
Except that Clang's error message requests for disambiguating template.


This issue came up while implementing @rule_of_zero at #797.
Fortunately, I could fix it with a local using std::ranges::empty; // Pending #506.
(std::views::empty actually came from using namespace std::views;).
So it doesn't directly use std::vector::empty.
I was fortunate enough to have such a fix-hack at hand.

@JohelEGP
Copy link
Contributor Author

JohelEGP commented Nov 7, 2023

I think this one really is IFNDR.
Reading https://eel.is/c++draft/algorithms.requirements#2
reminded me that the else branch,
although never taken for std::vector,
will always be ill-formed for all invocations (because std::views::empty needs a template argument).

@JohelEGP
Copy link
Contributor Author

JohelEGP commented Nov 7, 2023

IIRC from my analysis at #307, it's that this can't be solved without Cpp1 reflection.

@JohelEGP
Copy link
Contributor Author

JohelEGP commented Nov 9, 2023

The same seems to happen for operator(): https://compiler-explorer.com/z/65Y5rh7P5.

@JohelEGP
Copy link
Contributor Author

The one case we can handle is when source local name lookup results in a variable.
If it isn't templated, func<targs>(obj) can't be valid, so the only option is the member call.
See https://cpp2.godbolt.org/z/T6sdezYKh:

t: @struct type = {
  f: <T> (this) = { }
  g: <T> (this) = { }
}
main: () = {
  t().f<int>(); // OK.

  g := 0;
  // error: 'g' does not name a template but is followed by template arguments
  t().g<int>();
  _ = g;
}
auto main() -> int{
  CPP2_UFCS_TEMPLATE(f<int>)(t());// OK.
  auto g {0}; 
  CPP2_UFCS_TEMPLATE(g<int>)(t());// S
  static_cast<void>(std::move(g));
}
main.cpp2:10:22: error: 'g' does not name a template but is followed by template arguments
   10 |   CPP2_UFCS_TEMPLATE(g<int>)(t());
      |                      ^~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:855:84: note: expanded from macro 'CPP2_UFCS_TEMPLATE'
  855 | #define CPP2_UFCS_TEMPLATE(...)                           CPP2_UFCS_(&,(),template,__VA_ARGS__)
      |                                                                                    ^~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:845:51: note: expanded from macro 'CPP2_UFCS_'
  845 |   noexcept(CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,__VA_ARGS__)) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) \
      |                                                   ^~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:803:90: note: expanded from macro 'CPP2_UFCS_IS_NOTHROW_ARG'
  803 | #define CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,...)   CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,__VA_ARGS__)
      |                                                                                          ^~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:801:60: note: expanded from macro 'CPP2_UFCS_IS_NOTHROW'
  801 |               requires noexcept(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(std::declval<Obj>(), std::declval<Params>()...)); }
      |                                                            ^~~~~~~~~~~
main.cpp2:8:8: note: non-template declaration found by name lookup
    8 |   auto g {0}; 
      |        ^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant