116116 // in our -pure-cpp2 "import std;" simulation mode... if you need this,
117117 // use mixed mode (not -pure-cpp2) and #include all the headers you need
118118 // including this one
119- //
119+ //
120120 // #include <execution>
121121 #ifdef __cpp_lib_expected
122122 #include < expected>
@@ -526,7 +526,7 @@ template<typename T>
526526auto Typeid () -> decltype(auto ) {
527527#ifdef CPP2_NO_RTTI
528528 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
530530 " 'any' dynamic casting is disabled with -fno-rtti" // make message available to hooked handlers
531531 );
532532#else
@@ -575,7 +575,7 @@ struct {
575575 template <typename T>
576576 [[nodiscard]] auto cpp2_new (auto && ...args) const -> std::shared_ptr<T> {
577577 // Prefer { } to ( ) as noted for unique.new
578- //
578+ //
579579 // Note this does mean we don't get the make_shared optimization a lot
580580 // of the time -- we can restore that as soon as make_shared improves to
581581 // allow list initialization. But the make_shared optimization isn't a
@@ -745,13 +745,22 @@ class out {
745745//
746746// -----------------------------------------------------------------------
747747//
748+ // Workaround <https://github.com/llvm/llvm-project/issues/70556>.
749+ #define CPP2_FORCE_INLINE_LAMBDA_CLANG /* empty */
750+
748751#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]]
751754 #define CPP2_LAMBDA_NO_DISCARD
752755#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
755764
756765 #if defined(__clang_major__)
757766 // Also check __cplusplus, only to satisfy Clang -pedantic-errors
@@ -776,85 +785,77 @@ class out {
776785 #endif
777786#endif
778787
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-
800788#define CPP2_UFCS_REMPARENS (...) __VA_ARGS__
801789
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
831815
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
840836
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)...); \
845848 } 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)...); \
847850 } \
848- }(PARAM1, __VA_ARGS__)
851+ }
849852
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__)
858859
859860
860861// -----------------------------------------------------------------------
@@ -914,7 +915,7 @@ inline auto to_string(std::string const& s) -> std::string const&
914915
915916template <typename T>
916917inline 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>
918919 && !std::is_convertible_v<T, const char *>)
919920{
920921 return std::string{sv};
@@ -1054,17 +1055,17 @@ auto is( X const& ) -> bool {
10541055
10551056template < typename C, typename X >
10561057 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>)
10591060 ) && !std::is_same_v<C,X>)
10601061auto is ( X const & x ) -> bool {
10611062 return Dynamic_cast<C const *>(&x) != nullptr ;
10621063}
10631064
10641065template < typename C, typename X >
10651066 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>)
10681069 ) && !std::is_same_v<C,X>)
10691070auto is ( X const * x ) -> bool {
10701071 return Dynamic_cast<C const *>(x) != nullptr ;
@@ -1726,7 +1727,7 @@ constexpr auto unsafe_narrow( X&& x ) noexcept -> decltype(auto)
17261727// Returns a function object that takes a 'value' of the same type as
17271728// 'flags', and evaluates to true if and only if 'value' has set all of
17281729// the bits set in 'flags'
1729- //
1730+ //
17301731// -----------------------------------------------------------------------
17311732//
17321733template <typename T>
0 commit comments