@@ -174,14 +174,21 @@ namespace Catch {
174174 // should also be thread local. For now we just use naked globals
175175 // below, in the future we will want to allocate piece of memory
176176 // from heap, to avoid consuming too much thread-local storage.
177+ //
178+ // Note that we also don't want non-trivial the thread-local variables
179+ // below be initialized for every thread, only for those that touch
180+ // Catch2. To make this work with both GCC/Clang and MSVC, we have to
181+ // make them thread-local magic statics. (Class-level statics have the
182+ // desired semantics on GCC, but not on MSVC).
177183
178184 // This is used for the "if" part of CHECKED_IF/CHECKED_ELSE
179185 static CATCH_INTERNAL_THREAD_LOCAL bool g_lastAssertionPassed = false ;
180186
181187 // This is the source location for last encountered macro. It is
182188 // used to provide the users with more precise location of error
183189 // when an unexpected exception/fatal error happens.
184- static CATCH_INTERNAL_THREAD_LOCAL SourceLineInfo g_lastKnownLineInfo (" DummyLocation" , static_cast <size_t >(-1 ));
190+ static CATCH_INTERNAL_THREAD_LOCAL SourceLineInfo
191+ g_lastKnownLineInfo ( " DummyLocation" , static_cast <size_t >( -1 ) );
185192
186193 // Should we clear message scopes before sending off the messages to
187194 // reporter? Set in `assertionPassedFastPath` to avoid doing the full
@@ -191,10 +198,16 @@ namespace Catch {
191198 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
192199 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
193200 // Actual messages to be provided to the reporter
194- static CATCH_INTERNAL_THREAD_LOCAL std::vector<MessageInfo> g_messages;
201+ static std::vector<MessageInfo>& g_messages () {
202+ static CATCH_INTERNAL_THREAD_LOCAL std::vector<MessageInfo> value;
203+ return value;
204+ }
195205
196206 // Owners for the UNSCOPED_X information macro
197- static CATCH_INTERNAL_THREAD_LOCAL std::vector<ScopedMessage> g_messageScopes;
207+ static std::vector<ScopedMessage>& g_messageScopes () {
208+ static CATCH_INTERNAL_THREAD_LOCAL std::vector<ScopedMessage> value;
209+ return value;
210+ }
198211 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
199212
200213 } // namespace Detail
@@ -341,7 +354,7 @@ namespace Catch {
341354 }
342355
343356 if ( Detail::g_clearMessageScopes ) {
344- Detail::g_messageScopes.clear ();
357+ Detail::g_messageScopes () .clear ();
345358 Detail::g_clearMessageScopes = false ;
346359 }
347360
@@ -350,11 +363,11 @@ namespace Catch {
350363 {
351364 auto _ = scopedDeactivate ( *m_outputRedirect );
352365 updateTotalsFromAtomics ();
353- m_reporter->assertionEnded ( AssertionStats ( result, Detail::g_messages, m_totals ) );
366+ m_reporter->assertionEnded ( AssertionStats ( result, Detail::g_messages () , m_totals ) );
354367 }
355368
356369 if ( result.getResultType () != ResultWas::Warning ) {
357- Detail::g_messageScopes.clear ();
370+ Detail::g_messageScopes () .clear ();
358371 }
359372
360373 // Reset working state. assertion info will be reset after
@@ -643,10 +656,10 @@ namespace Catch {
643656
644657 m_testCaseTracker->close ();
645658 handleUnfinishedSections ();
646- Detail::g_messageScopes.clear ();
659+ Detail::g_messageScopes () .clear ();
647660 // TBD: At this point, m_messages should be empty. Do we want to
648661 // assert that this is true, or keep the defensive clear call?
649- Detail::g_messages.clear ();
662+ Detail::g_messages () .clear ();
650663
651664 SectionStats testCaseSectionStats (CATCH_MOVE (testCaseSection), assertions, duration, missingAssertions);
652665 m_reporter->sectionEnded (testCaseSectionStats);
@@ -814,7 +827,7 @@ namespace Catch {
814827 }
815828
816829 void IResultCapture::pushScopedMessage ( MessageInfo&& message ) {
817- Detail::g_messages.push_back ( CATCH_MOVE ( message ) );
830+ Detail::g_messages () .push_back ( CATCH_MOVE ( message ) );
818831 }
819832
820833 void IResultCapture::popScopedMessage ( unsigned int messageId ) {
@@ -823,12 +836,13 @@ namespace Catch {
823836 // messages than low single digits, so the optimization is tiny,
824837 // and we would have to hand-write the loop to avoid terrible
825838 // codegen of reverse iterators in debug mode.
826- Detail::g_messages.erase ( std::find_if ( Detail::g_messages.begin (),
827- Detail::g_messages.end (),
828- [=]( MessageInfo const & msg ) {
829- return msg.sequence ==
830- messageId;
831- } ) );
839+ auto & messages = Detail::g_messages ();
840+ messages.erase ( std::find_if ( messages.begin (),
841+ messages.end (),
842+ [=]( MessageInfo const & msg ) {
843+ return msg.sequence ==
844+ messageId;
845+ } ) );
832846 }
833847
834848 void IResultCapture::emplaceUnscopedMessage ( MessageBuilder&& builder ) {
@@ -837,10 +851,10 @@ namespace Catch {
837851 // delayed clear in assertion handling will erase the valid ones
838852 // as well.
839853 if ( Detail::g_clearMessageScopes ) {
840- Detail::g_messageScopes.clear ();
854+ Detail::g_messageScopes () .clear ();
841855 Detail::g_clearMessageScopes = false ;
842856 }
843- Detail::g_messageScopes.emplace_back ( CATCH_MOVE ( builder ) );
857+ Detail::g_messageScopes () .emplace_back ( CATCH_MOVE ( builder ) );
844858 }
845859
846860 void seedRng (IConfig const & config) {
0 commit comments