|
27 | 27 | // 2) Entities in namespace cpp2::impl::, and macros |
28 | 28 | // |
29 | 29 | // These should not be used by the program. They form the language |
30 | | -// support library intended to be called only from generated Cpp2 code. |
| 30 | +// support library intended to be called only from generated code. |
31 | 31 | // |
32 | 32 | // For example, if a Cpp2 function leaves a local variable |
33 | 33 | // uninitialized, cppfront will generate uses of impl::deferred_init<> |
@@ -887,6 +887,7 @@ class out { |
887 | 887 | #endif |
888 | 888 | #endif |
889 | 889 |
|
| 890 | +#define CPP2_UFCS_EMPTY(...) |
890 | 891 | #define CPP2_UFCS_IDENTITY(...) __VA_ARGS__ |
891 | 892 | #define CPP2_UFCS_REMPARENS(...) __VA_ARGS__ |
892 | 893 |
|
@@ -937,30 +938,49 @@ class out { |
937 | 938 | #define CPP2_UFCS_CONSTRAINT_ARG(...) IsViable |
938 | 939 | #endif |
939 | 940 |
|
940 | | -#define CPP2_UFCS_(LAMBDADEFCAPT,MVFWD,QUALID,TEMPKW,...) \ |
| 941 | +template <class T> struct dependent_false : std::false_type {}; |
| 942 | + |
| 943 | +#define CPP2_UFCS_(LAMBDADEFCAPT,SFINAE,MVFWD,QUALID,TEMPKW,...) \ |
941 | 944 | [LAMBDADEFCAPT]< \ |
942 | 945 | typename Obj, typename... Params \ |
943 | 946 | CPP2_UFCS_IS_NOTHROW_PARAM(MVFWD,QUALID,TEMPKW,__VA_ARGS__) \ |
944 | 947 | CPP2_UFCS_CONSTRAINT_PARAM(MVFWD,QUALID,TEMPKW,__VA_ARGS__) \ |
945 | 948 | > \ |
946 | 949 | CPP2_LAMBDA_NO_DISCARD (Obj&& obj, Params&& ...params) CPP2_FORCE_INLINE_LAMBDA_CLANG \ |
947 | 950 | noexcept(CPP2_UFCS_IS_NOTHROW_ARG(MVFWD,QUALID,TEMPKW,__VA_ARGS__)) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) \ |
948 | | - requires CPP2_UFCS_CONSTRAINT_ARG(MVFWD,QUALID,TEMPKW,__VA_ARGS__) { \ |
949 | | - if constexpr (requires{ CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); }) { \ |
950 | | - return CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); \ |
951 | | - } else { \ |
952 | | - return MVFWD(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__)(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \ |
| 951 | + SFINAE( requires CPP2_UFCS_CONSTRAINT_ARG(MVFWD,QUALID,TEMPKW,__VA_ARGS__) ) \ |
| 952 | + { \ |
| 953 | + if constexpr (requires{ CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); }) { \ |
| 954 | + return CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); \ |
953 | 955 | } \ |
954 | | -} |
955 | | - |
956 | | -#define CPP2_UFCS(...) CPP2_UFCS_(&,CPP2_UFCS_IDENTITY,(),,__VA_ARGS__) |
957 | | -#define CPP2_UFCS_MOVE(...) CPP2_UFCS_(&,std::move,(),,__VA_ARGS__) |
958 | | -#define CPP2_UFCS_FORWARD(...) CPP2_UFCS_(&,CPP2_FORWARD,(),,__VA_ARGS__) |
959 | | -#define CPP2_UFCS_TEMPLATE(...) CPP2_UFCS_(&,CPP2_UFCS_IDENTITY,(),template,__VA_ARGS__) |
960 | | -#define CPP2_UFCS_QUALIFIED_TEMPLATE(QUALID,...) CPP2_UFCS_(&,CPP2_UFCS_IDENTITY,QUALID,template,__VA_ARGS__) |
961 | | -#define CPP2_UFCS_NONLOCAL(...) CPP2_UFCS_(,CPP2_UFCS_IDENTITY,(),,__VA_ARGS__) |
962 | | -#define CPP2_UFCS_TEMPLATE_NONLOCAL(...) CPP2_UFCS_(,CPP2_UFCS_IDENTITY,(),template,__VA_ARGS__) |
963 | | -#define CPP2_UFCS_QUALIFIED_TEMPLATE_NONLOCAL(QUALID,...) CPP2_UFCS_(,CPP2_UFCS_IDENTITY,QUALID,template,__VA_ARGS__) |
| 956 | + else if constexpr (requires{ MVFWD(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__)(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); }) { \ |
| 957 | + return MVFWD(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__)(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \ |
| 958 | + } \ |
| 959 | + else if constexpr (requires{ obj.CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); }) { \ |
| 960 | + static_assert( cpp2::impl::dependent_false<Obj>::value, "this function call syntax tries 'obj.func(...)', then 'func(obj,...);' - both failed, but the first would have succeeded if obj were an lvalue - the likely problem is that this is a definite last use of the object (which automatically treats it as an rvalue / move candidate), and the function cannot accept an rvalue" ); \ |
| 961 | + CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); \ |
| 962 | + MVFWD(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__)(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \ |
| 963 | + } \ |
| 964 | + else if constexpr (requires{ MVFWD(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__)(obj, CPP2_FORWARD(params)...); }) { \ |
| 965 | + static_assert( cpp2::impl::dependent_false<Obj>::value, "this function call syntax tries 'obj.func(...)', then 'func(obj,...);' - both failed, but the second would have succeeded if obj were an lvalue - the likely problem is that this is a definite last use of the object, (which automatically treats it as an rvalue / move candidate) and the function cannot accept an rvalue" ); \ |
| 966 | + CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); \ |
| 967 | + MVFWD(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__)(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \ |
| 968 | + } \ |
| 969 | + else { \ |
| 970 | + static_assert( cpp2::impl::dependent_false<Obj>::value, "this function call syntax tries 'obj.func(...)', then 'func(obj,...);' - both failed, did you spell the function name correctly?" ); \ |
| 971 | + CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); \ |
| 972 | + MVFWD(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__)(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \ |
| 973 | + } \ |
| 974 | + } |
| 975 | + |
| 976 | +#define CPP2_UFCS(...) CPP2_UFCS_(&,CPP2_UFCS_EMPTY,CPP2_UFCS_IDENTITY,(),,__VA_ARGS__) |
| 977 | +#define CPP2_UFCS_MOVE(...) CPP2_UFCS_(&,CPP2_UFCS_EMPTY,std::move,(),,__VA_ARGS__) |
| 978 | +#define CPP2_UFCS_FORWARD(...) CPP2_UFCS_(&,CPP2_UFCS_EMPTY,CPP2_FORWARD,(),,__VA_ARGS__) |
| 979 | +#define CPP2_UFCS_TEMPLATE(...) CPP2_UFCS_(&,CPP2_UFCS_EMPTY,CPP2_UFCS_IDENTITY,(),template,__VA_ARGS__) |
| 980 | +#define CPP2_UFCS_QUALIFIED_TEMPLATE(QUALID,...) CPP2_UFCS_(&,CPP2_UFCS_EMPTY,CPP2_UFCS_IDENTITY,QUALID,template,__VA_ARGS__) |
| 981 | +#define CPP2_UFCS_NONLOCAL(...) CPP2_UFCS_(,CPP2_UFCS_IDENTITY,CPP2_UFCS_IDENTITY,(),,__VA_ARGS__) |
| 982 | +#define CPP2_UFCS_TEMPLATE_NONLOCAL(...) CPP2_UFCS_(,CPP2_UFCS_IDENTITY,CPP2_UFCS_IDENTITY,(),template,__VA_ARGS__) |
| 983 | +#define CPP2_UFCS_QUALIFIED_TEMPLATE_NONLOCAL(QUALID,...) CPP2_UFCS_(,CPP2_UFCS_IDENTITY,CPP2_UFCS_IDENTITY,QUALID,template,__VA_ARGS__) |
964 | 984 |
|
965 | 985 | } // impl |
966 | 986 |
|
|
0 commit comments