diff options
| author | Martin Hořeňovský | 2025-12-28 22:31:54 +0100 |
|---|---|---|
| committer | Martin Hořeňovský | 2025-12-28 22:31:54 +0100 |
| commit | 88abf9bf325c798c33f54f6b9220ef885b267f4f (patch) | |
| tree | 4b1a63974a61836ff064cd28c7ac9d8a7cb9efdb /extras | |
| parent | 970ec144f56d78703c51d08a855844e91c8560a8 (diff) | |
| download | catch3-3.12.0.tar.gz | |
v3.12.0v3.12.0
Diffstat (limited to 'extras')
| -rw-r--r-- | extras/catch_amalgamated.cpp | 195 | ||||
| -rw-r--r-- | extras/catch_amalgamated.hpp | 261 |
2 files changed, 290 insertions, 166 deletions
diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp index 892d637d..a4406d0c 100644 --- a/extras/catch_amalgamated.cpp +++ b/extras/catch_amalgamated.cpp @@ -6,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.11.0 -// Generated: 2025-09-30 10:49:12.549018 +// Catch v3.12.0 +// Generated: 2025-12-28 22:27:25.828797 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -2045,6 +2045,36 @@ namespace Detail { } } // end unnamed namespace + std::size_t catch_strnlen( const char* str, std::size_t n ) { + auto ret = std::char_traits<char>::find( str, n, '\0' ); + if ( ret != nullptr ) { return static_cast<std::size_t>( ret - str ); } + return n; + } + + std::string formatTimeT(std::time_t time) { +#ifdef _MSC_VER + std::tm timeInfo = {}; + const auto err = gmtime_s( &timeInfo, &time ); + if ( err ) { + return "gmtime from provided timepoint has failed. This " + "happens e.g. with pre-1970 dates using Microsoft libc"; + } +#else + std::tm* timeInfo = std::gmtime( &time ); +#endif + + auto const timeStampSize = sizeof( "2017-01-16T17:06:45Z" ); + char timeStamp[timeStampSize]; + const char* const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime( timeStamp, timeStampSize, fmt, &timeInfo ); +#else + std::strftime( timeStamp, timeStampSize, fmt, timeInfo ); +#endif + return std::string( timeStamp, timeStampSize - 1 ); + } + std::string convertIntoString(StringRef string, bool escapeInvisibles) { std::string ret; // This is enough for the "don't escape invisibles" case, and a good @@ -2354,7 +2384,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 11, 0, "", 0 ); + static Version version( 3, 12, 0, "", 0 ); return version; } @@ -3402,7 +3432,7 @@ namespace Catch { ( "list all listeners" ) | Opt( setTestOrder, "decl|lex|rand" ) ["--order"] - ( "test case order (defaults to decl)" ) + ( "test case order (defaults to rand)" ) | Opt( setRngSeed, "'time'|'random-device'|number" ) ["--rng-seed"] ( "set a specific seed for random numbers" ) @@ -3602,7 +3632,9 @@ namespace { #if defined( CATCH_PLATFORM_LINUX ) \ || defined( CATCH_PLATFORM_MAC ) \ || defined( __GLIBC__ ) \ - || defined( __FreeBSD__ ) \ + || (defined( __FreeBSD__ ) \ + /* PlayStation platform does not have `isatty()` */ \ + && !defined(CATCH_PLATFORM_PLAYSTATION)) \ || defined( CATCH_PLATFORM_QNX ) # define CATCH_INTERNAL_HAS_ISATTY # include <unistd.h> @@ -4886,19 +4918,22 @@ int main (int argc, char * argv[]) { namespace Catch { + namespace { + // Messages are owned by their individual threads, so the counter should + // be thread-local as well. Alternative consideration: atomic counter, + // so threads don't share IDs and things are easier to debug. + static CATCH_INTERNAL_THREAD_LOCAL unsigned int messageIDCounter = 0; + } + MessageInfo::MessageInfo( StringRef _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ) : macroName( _macroName ), lineInfo( _lineInfo ), type( _type ), - sequence( ++globalCount ) + sequence( ++messageIDCounter ) {} - // Messages are owned by their individual threads, so the counter should be thread-local as well. - // Alternative consideration: atomic, so threads don't share IDs and things are easier to debug. - thread_local unsigned int MessageInfo::globalCount = 0; - } // end namespace Catch @@ -5814,12 +5849,8 @@ namespace Catch { for ( auto const& child : m_children ) { if ( child->isSectionTracker() && - std::find( filters.begin(), - filters.end(), - static_cast<SectionTracker const&>( - *child ) - .trimmedName() ) != - filters.end() ) { + static_cast<SectionTracker const&>( *child ) + .trimmedName() == filters[0] ) { return true; } } @@ -5862,27 +5893,98 @@ namespace Catch { // should also be thread local. For now we just use naked globals // below, in the future we will want to allocate piece of memory // from heap, to avoid consuming too much thread-local storage. + // + // Note that we also don't want non-trivial the thread-local variables + // below be initialized for every thread, only for those that touch + // Catch2. To make this work with both GCC/Clang and MSVC, we have to + // make them thread-local magic statics. (Class-level statics have the + // desired semantics on GCC, but not on MSVC). // This is used for the "if" part of CHECKED_IF/CHECKED_ELSE - static thread_local bool g_lastAssertionPassed = false; + static CATCH_INTERNAL_THREAD_LOCAL bool g_lastAssertionPassed = false; // This is the source location for last encountered macro. It is // used to provide the users with more precise location of error // when an unexpected exception/fatal error happens. - static thread_local SourceLineInfo g_lastKnownLineInfo("DummyLocation", static_cast<size_t>(-1)); + static CATCH_INTERNAL_THREAD_LOCAL SourceLineInfo + g_lastKnownLineInfo( "DummyLocation", static_cast<size_t>( -1 ) ); // Should we clear message scopes before sending off the messages to // reporter? Set in `assertionPassedFastPath` to avoid doing the full // clear there for performance reasons. - static thread_local bool g_clearMessageScopes = false; + static CATCH_INTERNAL_THREAD_LOCAL bool g_clearMessageScopes = false; + + + // Holds the data for both scoped and unscoped messages together, + // to avoid issues where their lifetimes start in wrong order, + // and then are destroyed in wrong order. + class MessageHolder { + // The actual message vector passed to the reporters + std::vector<MessageInfo> messages; + // IDs of messages from UNSCOPED_X macros, which we have to + // remove manually. + std::vector<unsigned int> unscoped_ids; + + public: + // We do not need to special-case the unscoped messages when + // we only keep around the raw msg ids. + ~MessageHolder() = default; + + + void addUnscopedMessage(MessageBuilder&& builder) { + repairUnscopedMessageInvariant(); + MessageInfo info( CATCH_MOVE( builder.m_info ) ); + info.message = builder.m_stream.str(); + unscoped_ids.push_back( info.sequence ); + messages.push_back( CATCH_MOVE( info ) ); + } + + void addScopedMessage(MessageInfo&& info) { + messages.push_back( CATCH_MOVE( info ) ); + } + + std::vector<MessageInfo> const& getMessages() const { + return messages; + } + + void removeMessage( unsigned int messageId ) { + // Note: On average, it would probably be better to look for + // the message backwards. However, we do not expect to have + // to deal with more messages than low single digits, so + // the improvement is tiny, and we would have to hand-write + // the loop to avoid terrible codegen of reverse iterators + // in debug mode. + auto iter = + std::find_if( messages.begin(), + messages.end(), + [messageId]( MessageInfo const& msg ) { + return msg.sequence == messageId; + } ); + assert( iter != messages.end() && + "Trying to remove non-existent message." ); + messages.erase( iter ); + } + + void removeUnscopedMessages() { + for ( const auto messageId : unscoped_ids ) { + removeMessage( messageId ); + } + unscoped_ids.clear(); + g_clearMessageScopes = false; + } + + void repairUnscopedMessageInvariant() { + if ( g_clearMessageScopes ) { removeUnscopedMessages(); } + g_clearMessageScopes = false; + } + }; CATCH_INTERNAL_START_WARNINGS_SUPPRESSION CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS - // Actual messages to be provided to the reporter - static thread_local std::vector<MessageInfo> g_messages; - - // Owners for the UNSCOPED_X information macro - static thread_local std::vector<ScopedMessage> g_messageScopes; + static MessageHolder& g_messageHolder() { + static CATCH_INTERNAL_THREAD_LOCAL MessageHolder value; + return value; + } CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION } // namespace Detail @@ -5899,6 +6001,13 @@ namespace Catch { { getCurrentMutableContext().setResultCapture( this ); m_reporter->testRunStarting(m_runInfo); + + // TODO: HACK! + // We need to make sure the underlying cache is initialized + // while we are guaranteed to be running in a single thread, + // because the initialization is not thread-safe. + ReusableStringStream rss; + (void)rss; } RunContext::~RunContext() { @@ -6021,21 +6130,19 @@ namespace Catch { Detail::g_lastAssertionPassed = true; } - if ( Detail::g_clearMessageScopes ) { - Detail::g_messageScopes.clear(); - Detail::g_clearMessageScopes = false; - } + auto& msgHolder = Detail::g_messageHolder(); + msgHolder.repairUnscopedMessageInvariant(); // From here, we are touching shared state and need mutex. Detail::LockGuard lock( m_assertionMutex ); { auto _ = scopedDeactivate( *m_outputRedirect ); updateTotalsFromAtomics(); - m_reporter->assertionEnded( AssertionStats( result, Detail::g_messages, m_totals ) ); + m_reporter->assertionEnded( AssertionStats( result, msgHolder.getMessages(), m_totals ) ); } if ( result.getResultType() != ResultWas::Warning ) { - Detail::g_messageScopes.clear(); + msgHolder.removeUnscopedMessages(); } // Reset working state. assertion info will be reset after @@ -6324,10 +6431,10 @@ namespace Catch { m_testCaseTracker->close(); handleUnfinishedSections(); - Detail::g_messageScopes.clear(); - // TBD: At this point, m_messages should be empty. Do we want to - // assert that this is true, or keep the defensive clear call? - Detail::g_messages.clear(); + auto& msgHolder = Detail::g_messageHolder(); + msgHolder.removeUnscopedMessages(); + assert( msgHolder.getMessages().empty() && + "There should be no leftover messages after the test ends" ); SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); @@ -6495,25 +6602,15 @@ namespace Catch { } void IResultCapture::pushScopedMessage( MessageInfo&& message ) { - Detail::g_messages.push_back( CATCH_MOVE( message ) ); + Detail::g_messageHolder().addScopedMessage( CATCH_MOVE( message ) ); } void IResultCapture::popScopedMessage( unsigned int messageId ) { - // Note: On average, it would probably be better to look for the message - // backwards. However, we do not expect to have to deal with more - // messages than low single digits, so the optimization is tiny, - // and we would have to hand-write the loop to avoid terrible - // codegen of reverse iterators in debug mode. - Detail::g_messages.erase( std::find_if( Detail::g_messages.begin(), - Detail::g_messages.end(), - [=]( MessageInfo const& msg ) { - return msg.sequence == - messageId; - } ) ); + Detail::g_messageHolder().removeMessage( messageId ); } void IResultCapture::emplaceUnscopedMessage( MessageBuilder&& builder ) { - Detail::g_messageScopes.emplace_back( CATCH_MOVE( builder ) ); + Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) ); } void seedRng(IConfig const& config) { @@ -7219,9 +7316,9 @@ namespace TestCaseTracking { bool SectionTracker::isComplete() const { bool complete = true; - if (m_filters.empty() + if ( m_filters.empty() || m_filters[0].empty() - || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { + || m_filters[0] == m_trimmed_name ) { complete = TrackerBase::isComplete(); } return complete; diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp index d5eb1bb7..00fc3ee1 100644 --- a/extras/catch_amalgamated.hpp +++ b/extras/catch_amalgamated.hpp @@ -6,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.11.0 -// Generated: 2025-09-30 10:49:11.225746 +// Catch v3.12.0 +// Generated: 2025-12-28 22:27:25.408132 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -694,11 +694,30 @@ namespace Catch { #ifndef CATCH_STRINGREF_HPP_INCLUDED #define CATCH_STRINGREF_HPP_INCLUDED + + + +#ifndef CATCH_LIFETIMEBOUND_HPP_INCLUDED +#define CATCH_LIFETIMEBOUND_HPP_INCLUDED + +#if !defined( __has_cpp_attribute ) +# define CATCH_ATTR_LIFETIMEBOUND +#elif __has_cpp_attribute( msvc::lifetimebound ) +# define CATCH_ATTR_LIFETIMEBOUND [[msvc::lifetimebound]] +#elif __has_cpp_attribute( clang::lifetimebound ) +# define CATCH_ATTR_LIFETIMEBOUND [[clang::lifetimebound]] +#elif __has_cpp_attribute( lifetimebound ) +# define CATCH_ATTR_LIFETIMEBOUND [[lifetimebound]] +#else +# define CATCH_ATTR_LIFETIMEBOUND +#endif + +#endif // CATCH_LIFETIMEBOUND_HPP_INCLUDED + #include <cstddef> #include <string> #include <iosfwd> #include <cassert> - #include <cstring> namespace Catch { @@ -722,14 +741,16 @@ namespace Catch { public: // construction constexpr StringRef() noexcept = default; - StringRef( char const* rawChars ) noexcept; + StringRef( char const* rawChars CATCH_ATTR_LIFETIMEBOUND ) noexcept; - constexpr StringRef( char const* rawChars, size_type size ) noexcept + constexpr StringRef( char const* rawChars CATCH_ATTR_LIFETIMEBOUND, + size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} - StringRef( std::string const& stdString ) noexcept + StringRef( + std::string const& stdString CATCH_ATTR_LIFETIMEBOUND ) noexcept : m_start( stdString.c_str() ), m_size( stdString.size() ) {} @@ -775,7 +796,7 @@ namespace Catch { } // Returns the current start pointer. May not be null-terminated. - constexpr char const* data() const noexcept { + constexpr char const* data() const noexcept CATCH_ATTR_LIFETIMEBOUND { return m_start; } @@ -2305,7 +2326,7 @@ namespace Catch { #ifndef CATCH_TOSTRING_HPP_INCLUDED #define CATCH_TOSTRING_HPP_INCLUDED - +#include <ctime> #include <vector> #include <cstddef> #include <type_traits> @@ -2473,13 +2494,9 @@ namespace Catch { namespace Detail { - inline std::size_t catch_strnlen(const char *str, std::size_t n) { - auto ret = std::char_traits<char>::find(str, n, '\0'); - if (ret != nullptr) { - return static_cast<std::size_t>(ret - str); - } - return n; - } + std::size_t catch_strnlen(const char *str, std::size_t n); + + std::string formatTimeT( std::time_t time ); constexpr StringRef unprintableString = "{?}"_sr; @@ -2844,44 +2861,38 @@ namespace Catch { // Separate std::tuple specialization #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) -#include <tuple> +# include <tuple> +# include <utility> namespace Catch { namespace Detail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size<Tuple>::value) - > - struct TupleElementPrinter { - static void print(const Tuple& tuple, std::ostream& os) { - os << (N ? ", " : " ") - << ::Catch::Detail::stringify(std::get<N>(tuple)); - TupleElementPrinter<Tuple, N + 1>::print(tuple, os); - } - }; - - template< - typename Tuple, - std::size_t N - > - struct TupleElementPrinter<Tuple, N, false> { - static void print(const Tuple&, std::ostream&) {} - }; - - } + template <typename Tuple, std::size_t... Is> + void PrintTuple( const Tuple& tuple, + std::ostream& os, + std::index_sequence<Is...> ) { + // 1 + Account for when the tuple is empty + char a[1 + sizeof...( Is )] = { + ( ( os << ( Is ? ", " : " " ) + << ::Catch::Detail::stringify( std::get<Is>( tuple ) ) ), + '\0' )... }; + (void)a; + } + } // namespace Detail - template<typename ...Types> + template <typename... Types> struct StringMaker<std::tuple<Types...>> { - static std::string convert(const std::tuple<Types...>& tuple) { + static std::string convert( const std::tuple<Types...>& tuple ) { ReusableStringStream rss; rss << '{'; - Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get()); + Detail::PrintTuple( + tuple, + rss.get(), + std::make_index_sequence<sizeof...( Types )>{} ); rss << " }"; return rss.str(); } }; -} +} // namespace Catch #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER #if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) @@ -3068,28 +3079,7 @@ struct ratio_string<std::milli> { const auto systemish = std::chrono::time_point_cast< std::chrono::system_clock::duration>( time_point ); const auto as_time_t = std::chrono::system_clock::to_time_t( systemish ); - -#ifdef _MSC_VER - std::tm timeInfo = {}; - const auto err = gmtime_s( &timeInfo, &as_time_t ); - if ( err ) { - return "gmtime from provided timepoint has failed. This " - "happens e.g. with pre-1970 dates using Microsoft libc"; - } -#else - std::tm* timeInfo = std::gmtime( &as_time_t ); -#endif - - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp, timeStampSize - 1); + return ::Catch::Detail::formatTimeT( as_time_t ); } }; } @@ -3984,8 +3974,6 @@ namespace Catch { bool operator < (MessageInfo const& other) const { return sequence < other.sequence; } - private: - static thread_local unsigned int globalCount; }; } // end namespace Catch @@ -7478,7 +7466,7 @@ namespace Catch { #define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MAJOR 3 -#define CATCH_VERSION_MINOR 11 +#define CATCH_VERSION_MINOR 12 #define CATCH_VERSION_PATCH 0 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED @@ -10094,8 +10082,8 @@ namespace Catch { class JsonValueWriter { public: - JsonValueWriter( std::ostream& os ); - JsonValueWriter( std::ostream& os, std::uint64_t indent_level ); + JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND ); + JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level ); JsonObjectWriter writeObject() &&; JsonArrayWriter writeArray() &&; @@ -10129,8 +10117,8 @@ namespace Catch { class JsonObjectWriter { public: - JsonObjectWriter( std::ostream& os ); - JsonObjectWriter( std::ostream& os, std::uint64_t indent_level ); + JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND ); + JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level ); JsonObjectWriter( JsonObjectWriter&& source ) noexcept; JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete; @@ -10148,8 +10136,8 @@ namespace Catch { class JsonArrayWriter { public: - JsonArrayWriter( std::ostream& os ); - JsonArrayWriter( std::ostream& os, std::uint64_t indent_level ); + JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND ); + JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level ); JsonArrayWriter( JsonArrayWriter&& source ) noexcept; JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete; @@ -10422,7 +10410,7 @@ namespace TestCaseTracking { StringRef name; SourceLineInfo location; - constexpr NameAndLocationRef( StringRef name_, + constexpr NameAndLocationRef( StringRef name_ CATCH_ATTR_LIFETIMEBOUND, SourceLineInfo location_ ): name( name_ ), location( location_ ) {} @@ -10622,7 +10610,7 @@ using TestCaseTracking::SectionTracker; #define CATCH_THREAD_SUPPORT_HPP_INCLUDED -#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS ) +#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS ) # include <atomic> # include <mutex> #endif @@ -10630,14 +10618,14 @@ using TestCaseTracking::SectionTracker; namespace Catch { namespace Detail { -#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS ) +#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS ) using Mutex = std::mutex; using LockGuard = std::lock_guard<std::mutex>; struct AtomicCounts { - std::atomic<std::uint64_t> passed = 0; - std::atomic<std::uint64_t> failed = 0; - std::atomic<std::uint64_t> failedButOk = 0; - std::atomic<std::uint64_t> skipped = 0; + std::atomic<std::uint64_t> passed{ 0 }; + std::atomic<std::uint64_t> failed{ 0 }; + std::atomic<std::uint64_t> failedButOk{ 0 }; + std::atomic<std::uint64_t> skipped{ 0 }; }; #else // ^^ Use actual mutex, lock and atomics // vv Dummy implementations for single-thread performance @@ -10942,10 +10930,10 @@ namespace Catch { //! Returns a new string without whitespace at the start/end std::string trim( std::string const& str ); //! Returns a substring of the original ref without whitespace. Beware lifetimes! - StringRef trim(StringRef ref); + StringRef trim( StringRef ref CATCH_ATTR_LIFETIMEBOUND ); // !!! Be aware, returns refs into original string - make sure original string outlives them - std::vector<StringRef> splitStringRef( StringRef str, char delimiter ); + std::vector<StringRef> splitStringRef( StringRef str CATCH_ATTR_LIFETIMEBOUND, char delimiter ); bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); /** @@ -10963,7 +10951,7 @@ namespace Catch { StringRef m_label; public: - constexpr pluralise(std::uint64_t count, StringRef label): + constexpr pluralise(std::uint64_t count, StringRef label CATCH_ATTR_LIFETIMEBOUND): m_count(count), m_label(label) {} @@ -11442,6 +11430,19 @@ namespace Catch { #endif // CATCH_TEXTFLOW_HPP_INCLUDED +#ifndef CATCH_THREAD_LOCAL_HPP_INCLUDED +#define CATCH_THREAD_LOCAL_HPP_INCLUDED + + +#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS ) +#define CATCH_INTERNAL_THREAD_LOCAL thread_local +#else +#define CATCH_INTERNAL_THREAD_LOCAL +#endif + +#endif // CATCH_THREAD_LOCAL_HPP_INCLUDED + + #ifndef CATCH_TO_STRING_HPP_INCLUDED #define CATCH_TO_STRING_HPP_INCLUDED @@ -11510,7 +11511,7 @@ namespace Catch { public: enum ForWhat { ForTextNodes, ForAttributes }; - constexpr XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes ): + constexpr XmlEncode( StringRef str CATCH_ATTR_LIFETIMEBOUND, ForWhat forWhat = ForTextNodes ): m_str( str ), m_forWhat( forWhat ) {} @@ -11528,7 +11529,7 @@ namespace Catch { class ScopedElement { public: - ScopedElement( XmlWriter* writer, XmlFormatting fmt ); + ScopedElement( XmlWriter* writer CATCH_ATTR_LIFETIMEBOUND, XmlFormatting fmt ); ScopedElement( ScopedElement&& other ) noexcept; ScopedElement& operator=( ScopedElement&& other ) noexcept; @@ -11560,7 +11561,7 @@ namespace Catch { XmlFormatting m_fmt; }; - XmlWriter( std::ostream& os ); + XmlWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND ); ~XmlWriter(); XmlWriter( XmlWriter const& ) = delete; @@ -11818,11 +11819,15 @@ namespace Matchers { return description; } - friend MatchAllOf operator&& (MatchAllOf&& lhs, MatcherBase<ArgT> const& rhs) { + friend MatchAllOf operator&&( MatchAllOf&& lhs, + MatcherBase<ArgT> const& rhs + CATCH_ATTR_LIFETIMEBOUND ) { lhs.m_matchers.push_back(&rhs); return CATCH_MOVE(lhs); } - friend MatchAllOf operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf&& rhs) { + friend MatchAllOf + operator&&( MatcherBase<ArgT> const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAllOf&& rhs ) { rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs); return CATCH_MOVE(rhs); } @@ -11870,11 +11875,15 @@ namespace Matchers { return description; } - friend MatchAnyOf operator|| (MatchAnyOf&& lhs, MatcherBase<ArgT> const& rhs) { + friend MatchAnyOf operator||( MatchAnyOf&& lhs, + MatcherBase<ArgT> const& rhs + CATCH_ATTR_LIFETIMEBOUND ) { lhs.m_matchers.push_back(&rhs); return CATCH_MOVE(lhs); } - friend MatchAnyOf operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf&& rhs) { + friend MatchAnyOf + operator||( MatcherBase<ArgT> const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAnyOf&& rhs ) { rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs); return CATCH_MOVE(rhs); } @@ -11894,7 +11903,8 @@ namespace Matchers { MatcherBase<ArgT> const& m_underlyingMatcher; public: - explicit MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ): + explicit MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher + CATCH_ATTR_LIFETIMEBOUND ): m_underlyingMatcher( underlyingMatcher ) {} @@ -11910,16 +11920,22 @@ namespace Matchers { } // namespace Detail template <typename T> - Detail::MatchAllOf<T> operator&& (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) { + Detail::MatchAllOf<T> + operator&&( MatcherBase<T> const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherBase<T> const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchAllOf<T>{} && lhs && rhs; } + template <typename T> - Detail::MatchAnyOf<T> operator|| (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) { + Detail::MatchAnyOf<T> + operator||( MatcherBase<T> const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherBase<T> const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchAnyOf<T>{} || lhs || rhs; } template <typename T> - Detail::MatchNotOf<T> operator! (MatcherBase<T> const& matcher) { + Detail::MatchNotOf<T> + operator!( MatcherBase<T> const& matcher CATCH_ATTR_LIFETIMEBOUND ) { return Detail::MatchNotOf<T>{ matcher }; } @@ -12086,7 +12102,8 @@ namespace Matchers { MatchAllOfGeneric(MatchAllOfGeneric&&) = default; MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default; - MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {} + MatchAllOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND) + : m_matchers{ {std::addressof(matchers)...} } {} explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {} template<typename Arg> @@ -12108,8 +12125,8 @@ namespace Matchers { template<typename... MatchersRHS> friend MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && ( - MatchAllOfGeneric<MatcherTs...>&& lhs, - MatchAllOfGeneric<MatchersRHS...>&& rhs) { + MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAllOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAllOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))}; } @@ -12117,8 +12134,8 @@ namespace Matchers { template<typename MatcherRHS> friend std::enable_if_t<is_matcher_v<MatcherRHS>, MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && ( - MatchAllOfGeneric<MatcherTs...>&& lhs, - MatcherRHS const& rhs) { + MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAllOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(&rhs))}; } @@ -12126,8 +12143,8 @@ namespace Matchers { template<typename MatcherLHS> friend std::enable_if_t<is_matcher_v<MatcherLHS>, MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && ( - MatcherLHS const& lhs, - MatchAllOfGeneric<MatcherTs...>&& rhs) { + MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAllOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAllOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))}; } }; @@ -12141,7 +12158,8 @@ namespace Matchers { MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default; MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default; - MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {} + MatchAnyOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND) + : m_matchers{ {std::addressof(matchers)...} } {} explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {} template<typename Arg> @@ -12162,8 +12180,8 @@ namespace Matchers { //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case template<typename... MatchersRHS> friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || ( - MatchAnyOfGeneric<MatcherTs...>&& lhs, - MatchAnyOfGeneric<MatchersRHS...>&& rhs) { + MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAnyOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))}; } @@ -12171,8 +12189,8 @@ namespace Matchers { template<typename MatcherRHS> friend std::enable_if_t<is_matcher_v<MatcherRHS>, MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || ( - MatchAnyOfGeneric<MatcherTs...>&& lhs, - MatcherRHS const& rhs) { + MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND, + MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) { return MatchAnyOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(std::addressof(rhs)))}; } @@ -12180,8 +12198,8 @@ namespace Matchers { template<typename MatcherLHS> friend std::enable_if_t<is_matcher_v<MatcherLHS>, MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || ( - MatcherLHS const& lhs, - MatchAnyOfGeneric<MatcherTs...>&& rhs) { + MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND, + MatchAnyOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND) { return MatchAnyOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))}; } }; @@ -12197,7 +12215,8 @@ namespace Matchers { MatchNotOfGeneric(MatchNotOfGeneric&&) = default; MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default; - explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{mat |