diff --git a/CMakeLists.txt b/CMakeLists.txt
index 49d7879b..de5e6709 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,7 +35,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif()
project(Catch2
- VERSION 3.15.1 # CML version placeholder, don't delete
+ VERSION 3.15.2 # CML version placeholder, don't delete
LANGUAGES CXX
HOMEPAGE_URL "https://github.com/catchorg/Catch2"
DESCRIPTION "A modern, C++-native, unit test framework."
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 9f8b0979..ffa06430 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -2,6 +2,7 @@
# Release notes
**Contents**
+[3.15.2](#3152)
[3.15.1](#3151)
[3.15.0](#3150)
[3.14.0](#3140)
@@ -76,6 +77,16 @@
[Even Older versions](#even-older-versions)
+## 3.15.2
+
+### Fixes
+* Fixed `--warn InfiniteGenerators` triggering even if the generator was limited to specific element via path filtering.
+* Fixed `-Wunused-parameter` triggering in `-fnoexceptions` builds.
+
+### Improvements
+* `catch_discover_tests` can handle cases where the binary prints out non-Catch2 output due to global constructors (#3162)
+
+
## 3.15.1
### Fixes
diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp
index baf527f0..4e1e631e 100644
--- a/extras/catch_amalgamated.cpp
+++ b/extras/catch_amalgamated.cpp
@@ -6,8 +6,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.15.1
-// Generated: 2026-06-14 10:51:56.053498
+// Catch v3.15.2
+// Generated: 2026-07-07 20:39:49.445081
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -2394,7 +2394,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 3, 15, 1, "", 0 );
+ static Version version( 3, 15, 2, "", 0 );
return version;
}
@@ -6016,6 +6016,8 @@ namespace Catch {
auto getGenerator() const -> GeneratorBasePtr const& override {
return m_generator;
}
+
+ bool isFilteredImpl() const override { return m_isFiltered; }
};
} // namespace
}
@@ -6360,17 +6362,6 @@ namespace Catch {
SourceLineInfo lineInfo,
Generators::GeneratorBasePtr&& generator ) {
- // TBD: Do we want to avoid the warning if the generator is filtered?
- if ( m_config->warnAboutInfiniteGenerators() &&
- !generator->isFinite() ) {
- // We want the semantics of `FAIL()`, but we inline it
- // to avoid issues with conditionally prefixed macros
- INTERNAL_CATCH_MSG( "FAIL",
- Catch::ResultWas::ExplicitFailure,
- Catch::ResultDisposition::Normal,
- "GENERATE() would run infinitely" );
- }
-
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast( generatorName ), lineInfo );
auto& currentTracker = m_trackerContext.currentTracker();
assert(
@@ -6383,11 +6374,24 @@ namespace Catch {
m_trackerContext,
¤tTracker,
CATCH_MOVE( generator ) );
- auto ret = newTracker.get();
+
+ // The warning shouldn't fire if the generator is infinite, **but** filtered down.
+ if ( m_config->warnAboutInfiniteGenerators() &&
+ !newTracker->m_generator->isFinite() &&
+ !newTracker->isFiltered() ) {
+ // We want the semantics of `FAIL()`, but we inline it
+ // to avoid issues with conditionally prefixed macros
+ INTERNAL_CATCH_MSG( "FAIL",
+ Catch::ResultWas::ExplicitFailure,
+ Catch::ResultDisposition::Normal,
+ "GENERATE() would run infinitely" );
+ }
+
+ auto returnPtr = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
- ret->open();
- return ret;
+ returnPtr->open();
+ return returnPtr;
}
bool RunContext::testForMissingAssertions(Counts& assertions) {
@@ -7470,6 +7474,28 @@ namespace TestCaseTracking {
m_ctx.setCurrentTracker( this );
}
+ bool SectionTracker::isFilteredImpl() const {
+ // TBD: This is currently _very_ similar to the block in `isComplete`.
+ // Is this neccessarily that way, or just accident of current semantics?
+ const size_t filterIndex =
+ m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
+
+ if ( filterIndex < m_filterRef->size() ) {
+ // 1) New style filter must explicitly target section
+ if ( m_newStyleFilters && ( *m_filterRef )[filterIndex].type !=
+ PathFilter::For::Section ) {
+ return true;
+ }
+ // 2) Both style filters must match the trimmed name exactly
+ if ( m_trimmed_name !=
+ StringRef( ( *m_filterRef )[filterIndex].filter ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp
index fc71645c..7e65eb93 100644
--- a/extras/catch_amalgamated.hpp
+++ b/extras/catch_amalgamated.hpp
@@ -6,8 +6,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.15.1
-// Generated: 2026-06-14 10:51:55.600632
+// Catch v3.15.2
+// Generated: 2026-07-07 20:39:49.020441
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -7484,6 +7484,8 @@ namespace Catch {
return m_translateFunction( ex );
}
#else
+ (void)it;
+ (void)itEnd;
return "You should never get here!";
#endif
}
@@ -7570,7 +7572,7 @@ namespace Catch {
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 15
-#define CATCH_VERSION_PATCH 1
+#define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
@@ -7910,8 +7912,7 @@ namespace Generators {
bool isFinite() const override {
for (auto const& gen : m_generators) {
- if (!gen.isFinite()) { return false;
- }
+ if (!gen.isFinite()) { return false; }
}
return true;
}
@@ -10657,6 +10658,8 @@ namespace TestCaseTracking {
using Children = std::vector;
+ virtual bool isFilteredImpl() const = 0;
+
protected:
enum CycleState {
NotStarted,
@@ -10754,6 +10757,20 @@ namespace TestCaseTracking {
* for internal debug checks.
*/
virtual bool isGeneratorTracker() const;
+
+ /**
+ * Returns true if the concrete tracker instance has a filter that applies to it.
+ */
+ bool isFiltered() const {
+ // Fast path: are there even filters for tracker in this position?
+ const size_t filter_depth =
+ m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
+ if ( m_filterRef->size() <= filter_depth ) { return false; }
+
+ // Slow path: If there are filters, ask the concrete tracker.
+ // This handles things like match-all filters for that tracker.
+ return isFilteredImpl();
+ }
};
class TrackerContext {
@@ -10809,6 +10826,8 @@ namespace TestCaseTracking {
// to not own the name, the name still has to outlive the `ITracker` parent, so
// this should still be safe.
StringRef m_trimmed_name;
+
+ bool isFilteredImpl() const override;
public:
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
diff --git a/meson.build b/meson.build
index 57408666..25fb3c2d 100644
--- a/meson.build
+++ b/meson.build
@@ -8,7 +8,7 @@
project(
'catch2',
'cpp',
- version: '3.15.1', # CML version placeholder, don't delete
+ version: '3.15.2', # CML version placeholder, don't delete
license: 'BSL-1.0',
meson_version: '>=0.54.1',
)
diff --git a/src/catch2/catch_version.cpp b/src/catch2/catch_version.cpp
index c815dba5..47aef8e8 100644
--- a/src/catch2/catch_version.cpp
+++ b/src/catch2/catch_version.cpp
@@ -36,7 +36,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 3, 15, 1, "", 0 );
+ static Version version( 3, 15, 2, "", 0 );
return version;
}
diff --git a/src/catch2/catch_version_macros.hpp b/src/catch2/catch_version_macros.hpp
index f60b3199..71103dbf 100644
--- a/src/catch2/catch_version_macros.hpp
+++ b/src/catch2/catch_version_macros.hpp
@@ -10,6 +10,6 @@
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 15
-#define CATCH_VERSION_PATCH 1
+#define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED