Skip to content

Commit 7041994

Browse files
authored
Add UFCS failure case error diagnostics (#1023)
* Add UFCS failure case error diagnostics * Restore UFCS SFINAE test to just _NONLOCAL versions Per #1023 (comment) and followups
1 parent 515a74f commit 7041994

File tree

5 files changed

+137
-117
lines changed

5 files changed

+137
-117
lines changed

include/cpp2util.h

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
// 2) Entities in namespace cpp2::impl::, and macros
2828
//
2929
// 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.
3131
//
3232
// For example, if a Cpp2 function leaves a local variable
3333
// uninitialized, cppfront will generate uses of impl::deferred_init<>
@@ -887,6 +887,7 @@ class out {
887887
#endif
888888
#endif
889889

890+
#define CPP2_UFCS_EMPTY(...)
890891
#define CPP2_UFCS_IDENTITY(...) __VA_ARGS__
891892
#define CPP2_UFCS_REMPARENS(...) __VA_ARGS__
892893

@@ -937,30 +938,49 @@ class out {
937938
#define CPP2_UFCS_CONSTRAINT_ARG(...) IsViable
938939
#endif
939940

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,...) \
941944
[LAMBDADEFCAPT]< \
942945
typename Obj, typename... Params \
943946
CPP2_UFCS_IS_NOTHROW_PARAM(MVFWD,QUALID,TEMPKW,__VA_ARGS__) \
944947
CPP2_UFCS_CONSTRAINT_PARAM(MVFWD,QUALID,TEMPKW,__VA_ARGS__) \
945948
> \
946949
CPP2_LAMBDA_NO_DISCARD (Obj&& obj, Params&& ...params) CPP2_FORCE_INLINE_LAMBDA_CLANG \
947950
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)...); \
953955
} \
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__)
964984

965985
} // impl
966986

0 commit comments

Comments
 (0)