116
116
// in our -pure-cpp2 "import std;" simulation mode... if you need this,
117
117
// use mixed mode (not -pure-cpp2) and #include all the headers you need
118
118
// including this one
119
- //
119
+ //
120
120
// #include <execution>
121
121
#ifdef __cpp_lib_expected
122
122
#include < expected>
@@ -526,7 +526,7 @@ template<typename T>
526
526
auto Typeid () -> decltype(auto ) {
527
527
#ifdef CPP2_NO_RTTI
528
528
Type.expects (
529
- !" 'any' dynamic casting is disabled with -fno-rtti" , // more likely to appear on console
529
+ !" 'any' dynamic casting is disabled with -fno-rtti" , // more likely to appear on console
530
530
" 'any' dynamic casting is disabled with -fno-rtti" // make message available to hooked handlers
531
531
);
532
532
#else
@@ -575,7 +575,7 @@ struct {
575
575
template <typename T>
576
576
[[nodiscard]] auto cpp2_new (auto && ...args) const -> std::shared_ptr<T> {
577
577
// Prefer { } to ( ) as noted for unique.new
578
- //
578
+ //
579
579
// Note this does mean we don't get the make_shared optimization a lot
580
580
// of the time -- we can restore that as soon as make_shared improves to
581
581
// allow list initialization. But the make_shared optimization isn't a
@@ -745,13 +745,22 @@ class out {
745
745
//
746
746
// -----------------------------------------------------------------------
747
747
//
748
+ // Workaround <https://github.com/llvm/llvm-project/issues/70556>.
749
+ #define CPP2_FORCE_INLINE_LAMBDA_CLANG /* empty */
750
+
748
751
#if defined(_MSC_VER) && !defined(__clang_major__)
749
- #define CPP2_FORCE_INLINE __forceinline
750
- #define CPP2_FORCE_INLINE_LAMBDA [[msvc::forceinline]]
752
+ #define CPP2_FORCE_INLINE __forceinline
753
+ #define CPP2_FORCE_INLINE_LAMBDA [[msvc::forceinline]]
751
754
#define CPP2_LAMBDA_NO_DISCARD
752
755
#else
753
- #define CPP2_FORCE_INLINE __attribute__ ((always_inline))
754
- #define CPP2_FORCE_INLINE_LAMBDA __attribute__ ((always_inline))
756
+ #define CPP2_FORCE_INLINE __attribute__ ((always_inline))
757
+ #if defined (__clang__)
758
+ #define CPP2_FORCE_INLINE_LAMBDA /* empty */
759
+ #undef CPP2_FORCE_INLINE_LAMBDA_CLANG
760
+ #define CPP2_FORCE_INLINE_LAMBDA_CLANG __attribute__ ((always_inline))
761
+ #else
762
+ #define CPP2_FORCE_INLINE_LAMBDA __attribute__ ((always_inline))
763
+ #endif
755
764
756
765
#if defined(__clang_major__)
757
766
// Also check __cplusplus, only to satisfy Clang -pedantic-errors
@@ -776,85 +785,77 @@ class out {
776
785
#endif
777
786
#endif
778
787
779
-
780
- // Note: [&] is because a nested UFCS might be viewed as trying to capture 'this'
781
-
782
- #define CPP2_UFCS (FUNCNAME,PARAM1,...) \
783
- [&] CPP2_LAMBDA_NO_DISCARD (auto && obj, auto && ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) { \
784
- if constexpr (requires{ CPP2_FORWARD (obj).FUNCNAME (CPP2_FORWARD (params)...); }) { \
785
- return CPP2_FORWARD (obj).FUNCNAME (CPP2_FORWARD (params)...); \
786
- } else { \
787
- return FUNCNAME (CPP2_FORWARD (obj), CPP2_FORWARD (params)...); \
788
- } \
789
- }(PARAM1, __VA_ARGS__)
790
-
791
- #define CPP2_UFCS_0 (FUNCNAME,PARAM1 ) \
792
- [&] CPP2_LAMBDA_NO_DISCARD (auto && obj) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) { \
793
- if constexpr (requires{ CPP2_FORWARD (obj).FUNCNAME (); }) { \
794
- return CPP2_FORWARD (obj).FUNCNAME (); \
795
- } else { \
796
- return FUNCNAME (CPP2_FORWARD (obj)); \
797
- } \
798
- }(PARAM1)
799
-
800
788
#define CPP2_UFCS_REMPARENS (...) __VA_ARGS__
801
789
802
- #define CPP2_UFCS_TEMPLATE (FUNCNAME,TEMPARGS,PARAM1,...) \
803
- [&] CPP2_LAMBDA_NO_DISCARD (auto && obj, auto && ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) { \
804
- if constexpr (requires{ CPP2_FORWARD (obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD (params)...); }) { \
805
- return CPP2_FORWARD (obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD (params)...); \
806
- } else { \
807
- return FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD (obj), CPP2_FORWARD (params)...); \
808
- } \
809
- }(PARAM1, __VA_ARGS__)
810
-
811
- #define CPP2_UFCS_TEMPLATE_0 (FUNCNAME,TEMPARGS,PARAM1 ) \
812
- [&] CPP2_LAMBDA_NO_DISCARD (auto && obj) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) { \
813
- if constexpr (requires{ CPP2_FORWARD (obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (); }) { \
814
- return CPP2_FORWARD (obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (); \
815
- } else { \
816
- return FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD (obj)); \
817
- } \
818
- }(PARAM1)
819
-
820
-
821
- // But for non-local lambdas [&] is not allowed
822
-
823
- #define CPP2_UFCS_NONLOCAL (FUNCNAME,PARAM1,...) \
824
- [] CPP2_LAMBDA_NO_DISCARD (auto && obj, auto && ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) { \
825
- if constexpr (requires{ CPP2_FORWARD (obj).FUNCNAME (CPP2_FORWARD (params)...); }) { \
826
- return CPP2_FORWARD (obj).FUNCNAME (CPP2_FORWARD (params)...); \
827
- } else { \
828
- return FUNCNAME (CPP2_FORWARD (obj), CPP2_FORWARD (params)...); \
829
- } \
830
- }(PARAM1, __VA_ARGS__)
790
+ // Ideally, the expression `CPP2_UFCS_IS_NOTHROW` expands to
791
+ // is in the _noexcept-specifier_ of the UFCS lambda, but without 'std::declval'.
792
+ // To workaround [GCC bug 101043](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101043),
793
+ // we instead make it a template parameter of the UFCS lambda.
794
+ // But using a template parameter, Clang also ICEs on an application.
795
+ // So we use these `NOTHROW` macros to fall back to the ideal for when not using GCC.
796
+ #define CPP2_UFCS_IS_NOTHROW (QUALID,TEMPKW,...) \
797
+ requires { requires requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__ (std::declval<Params>()...); }; \
798
+ requires noexcept (std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__ (std::declval<Params>()...)); } \
799
+ || requires { requires !requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__ (std::declval<Params>()...); }; \
800
+ requires noexcept (CPP2_UFCS_REMPARENS QUALID __VA_ARGS__ (std::declval<Obj>(), std::declval<Params>()...)); }
801
+ #define CPP2_UFCS_IS_NOTHROW_PARAM (...) /* empty*/
802
+ #define CPP2_UFCS_IS_NOTHROW_ARG (QUALID,TEMPKW,...) CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,__VA_ARGS__)
803
+ #if defined(__GNUC__) && !defined(__clang__)
804
+ #undef CPP2_UFCS_IS_NOTHROW_PARAM
805
+ #undef CPP2_UFCS_IS_NOTHROW_ARG
806
+ #define CPP2_UFCS_IS_NOTHROW_PARAM (QUALID,TEMPKW,...) , bool IsNothrow = CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,__VA_ARGS__)
807
+ #define CPP2_UFCS_IS_NOTHROW_ARG (...) IsNothrow
808
+ #if __GNUC__ < 11
809
+ #undef CPP2_UFCS_IS_NOTHROW_PARAM
810
+ #undef CPP2_UFCS_IS_NOTHROW_ARG
811
+ #define CPP2_UFCS_IS_NOTHROW_PARAM (...) /* empty*/
812
+ #define CPP2_UFCS_IS_NOTHROW_ARG (...) false // GCC 10 UFCS is always potentially-throwing.
813
+ #endif
814
+ #endif
831
815
832
- #define CPP2_UFCS_0_NONLOCAL (FUNCNAME,PARAM1 ) \
833
- [] CPP2_LAMBDA_NO_DISCARD (auto && obj) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) { \
834
- if constexpr (requires{ CPP2_FORWARD (obj).FUNCNAME (); }) { \
835
- return CPP2_FORWARD (obj).FUNCNAME (); \
836
- } else { \
837
- return FUNCNAME (CPP2_FORWARD (obj)); \
838
- } \
839
- }(PARAM1)
816
+ // Ideally, the expression `CPP2_UFCS_CONSTRAINT_ARG` expands to
817
+ // is in the _requires-clause_ of the UFCS lambda.
818
+ // To workaround an MSVC bug within a member function 'F' where UFCS is also for 'F'
819
+ // (<https://github.com/hsutter/cppfront/pull/506#issuecomment-1826086952>),
820
+ // we instead make it a template parameter of the UFCS lambda.
821
+ // But using a template parameter, Clang also ICEs and GCC rejects a local 'F'.
822
+ // Also, Clang rejects the SFINAE test case when using 'std::declval'.
823
+ // So we use these `CONSTRAINT` macros to fall back to the ideal for when not using MSVC.
824
+ #define CPP2_UFCS_CONSTRAINT_PARAM (...) /* empty*/
825
+ #define CPP2_UFCS_CONSTRAINT_ARG (QUALID,TEMPKW,...) \
826
+ requires { CPP2_FORWARD (obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__ (CPP2_FORWARD (params)...); } \
827
+ || requires { CPP2_UFCS_REMPARENS QUALID __VA_ARGS__ (CPP2_FORWARD (obj), CPP2_FORWARD (params)...); }
828
+ #if defined(_MSC_VER)
829
+ #undef CPP2_UFCS_CONSTRAINT_PARAM
830
+ #undef CPP2_UFCS_CONSTRAINT_ARG
831
+ #define CPP2_UFCS_CONSTRAINT_PARAM (QUALID,TEMPKW,...) , bool IsViable = \
832
+ requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__ (std::declval<Params>()...); } \
833
+ || requires { CPP2_UFCS_REMPARENS QUALID __VA_ARGS__ (std::declval<Obj>(), std::declval<Params>()...); }
834
+ #define CPP2_UFCS_CONSTRAINT_ARG (...) IsViable
835
+ #endif
840
836
841
- #define CPP2_UFCS_TEMPLATE_NONLOCAL (FUNCNAME,TEMPARGS,PARAM1,...) \
842
- [] CPP2_LAMBDA_NO_DISCARD (auto && obj, auto && ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) { \
843
- if constexpr (requires{ CPP2_FORWARD (obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD (params)...); }) { \
844
- return CPP2_FORWARD (obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD (params)...); \
837
+ #define CPP2_UFCS_ (LAMBDADEFCAPT,QUALID,TEMPKW,...) \
838
+ [LAMBDADEFCAPT]< \
839
+ typename Obj, typename ... Params \
840
+ CPP2_UFCS_IS_NOTHROW_PARAM (QUALID,TEMPKW,__VA_ARGS__) \
841
+ CPP2_UFCS_CONSTRAINT_PARAM (QUALID,TEMPKW,__VA_ARGS__) \
842
+ > \
843
+ CPP2_LAMBDA_NO_DISCARD (Obj&& obj, Params&& ...params) CPP2_FORCE_INLINE_LAMBDA_CLANG \
844
+ noexcept (CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,__VA_ARGS__)) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) \
845
+ requires CPP2_UFCS_CONSTRAINT_ARG(QUALID,TEMPKW,__VA_ARGS__) { \
846
+ if constexpr (requires{ CPP2_FORWARD (obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__ (CPP2_FORWARD (params)...); }) { \
847
+ return CPP2_FORWARD (obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__ (CPP2_FORWARD (params)...); \
845
848
} else { \
846
- return FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD (obj), CPP2_FORWARD (params)...); \
849
+ return CPP2_UFCS_REMPARENS QUALID __VA_ARGS__ (CPP2_FORWARD (obj), CPP2_FORWARD (params)...); \
847
850
} \
848
- }(PARAM1, __VA_ARGS__)
851
+ }
849
852
850
- #define CPP2_UFCS_TEMPLATE_0_NONLOCAL (FUNCNAME,TEMPARGS,PARAM1 ) \
851
- [] CPP2_LAMBDA_NO_DISCARD (auto && obj) CPP2_FORCE_INLINE_LAMBDA -> decltype (auto ) { \
852
- if constexpr (requires{ CPP2_FORWARD (obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (); }) { \
853
- return CPP2_FORWARD (obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (); \
854
- } else { \
855
- return FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD (obj)); \
856
- } \
857
- }(PARAM1)
853
+ #define CPP2_UFCS (...) CPP2_UFCS_(&,(),,__VA_ARGS__)
854
+ #define CPP2_UFCS_TEMPLATE (...) CPP2_UFCS_(&,(),template ,__VA_ARGS__)
855
+ #define CPP2_UFCS_QUALIFIED_TEMPLATE (QUALID,...) CPP2_UFCS_(&,QUALID,template ,__VA_ARGS__)
856
+ #define CPP2_UFCS_NONLOCAL (...) CPP2_UFCS_(,(),,__VA_ARGS__)
857
+ #define CPP2_UFCS_TEMPLATE_NONLOCAL (...) CPP2_UFCS_(,(),template ,__VA_ARGS__)
858
+ #define CPP2_UFCS_QUALIFIED_TEMPLATE_NONLOCAL (QUALID,...) CPP2_UFCS_(,QUALID,template ,__VA_ARGS__)
858
859
859
860
860
861
// -----------------------------------------------------------------------
@@ -914,7 +915,7 @@ inline auto to_string(std::string const& s) -> std::string const&
914
915
915
916
template <typename T>
916
917
inline auto to_string (T const & sv) -> std::string
917
- requires (std::is_convertible_v<T, std::string_view>
918
+ requires (std::is_convertible_v<T, std::string_view>
918
919
&& !std::is_convertible_v<T, const char *>)
919
920
{
920
921
return std::string{sv};
@@ -1054,17 +1055,17 @@ auto is( X const& ) -> bool {
1054
1055
1055
1056
template < typename C, typename X >
1056
1057
requires (
1057
- ( std::is_base_of_v<X, C> ||
1058
- ( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
1058
+ ( std::is_base_of_v<X, C> ||
1059
+ ( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
1059
1060
) && !std::is_same_v<C,X>)
1060
1061
auto is ( X const & x ) -> bool {
1061
1062
return Dynamic_cast<C const *>(&x) != nullptr ;
1062
1063
}
1063
1064
1064
1065
template < typename C, typename X >
1065
1066
requires (
1066
- ( std::is_base_of_v<X, C> ||
1067
- ( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
1067
+ ( std::is_base_of_v<X, C> ||
1068
+ ( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
1068
1069
) && !std::is_same_v<C,X>)
1069
1070
auto is ( X const * x ) -> bool {
1070
1071
return Dynamic_cast<C const *>(x) != nullptr ;
@@ -1726,7 +1727,7 @@ constexpr auto unsafe_narrow( X&& x ) noexcept -> decltype(auto)
1726
1727
// Returns a function object that takes a 'value' of the same type as
1727
1728
// 'flags', and evaluates to true if and only if 'value' has set all of
1728
1729
// the bits set in 'flags'
1729
- //
1730
+ //
1730
1731
// -----------------------------------------------------------------------
1731
1732
//
1732
1733
template <typename T>
0 commit comments