Repository navigation
doc: fix the custom RTTI examples; build: warning flags on the examples - #129
Merged
Merged
Conversation
Both examples returned `reinterpret_cast<type_id>(0)` for every type that does not derive from `Node`. That looks harmless - such types never take part in dispatch - but `static_type` is also how a *method* is identified, and a `method<...>` specialization is not derived from `Node`, so it takes that branch too. `augment_methods` keys `method_map` on the method's type id, so every method in the registry lands under the same key: they merge into one, their overriders pool together, nothing dominates, and the first call reaches `fn_ambiguous`. Neither example's registry has an `error_handler` or an `output` policy, so it aborts with no message at all. Each example declares exactly one method, so nothing merges today and the examples work. It bites the reader who follows the page and adds a second method, which is the obvious next step. Demonstrated by adding a `depth` method to each example: before, abort with exit 134; after, `2 3 + 4 * = 20 depth=3`. Non-polymorphic types now get the address of a function-local static, which is what the library's own `static_rtti` policy does, and `dynamic_type` delegates to `static_type` so the two cannot disagree. The page gains a paragraph on why the placeholder is a trap, and the sentence promising a "small, dense range" of ids is narrowed to the classes that take part in dispatch - which is what `vptr_vector` indexes. Every other custom `static_type` in the tree - the `static_rtti` and `named_static_rtti` policies, and the five tests that define one - already gives non-polymorphic types distinct ids. Only the examples were wrong, which is why no test caught it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Eo4q4cYTx457W7oaunqsQ
|
An automated preview of the documentation is available at https://129.openmethod.prtest3.cppalliance.org/libs/openmethod/doc/html/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-10-10 17:14:10 UTC |
`call_via_ref` was copied from the first example, where `postfix` writes to
the stream. The second example evaluates instead - the body is
`return value(node)` - so `os` has been unused ever since, and the example
does not compile under -Wall -Wextra -Werror:
custom_rtti.cpp:118:51: error: unused parameter 'os'
[-Werror=unused-parameter]
The examples are not built with -Wextra, which is why it went unnoticed.
The function sits outside every doc tag, so nothing renders it;
`performance.adoc` discusses a `call_via_ref` of its own, written inline and
taking the stream, and the first example keeps its two-parameter version.
Both examples now compile clean at -Wall -Wextra -Werror.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Eo4q4cYTx457W7oaunqsQ
There is no Jamfile under doc/modules/ROOT/examples, so b2 never compiles
the examples, and the CMake build - the only check they get - was passing
them no warning flags at all. Mirror test/CMakeLists.txt: the flags go on
under BOOST_OPENMETHOD_WARNINGS_AS_ERRORS, which the C++26 reflection job
sets, and that job builds the examples because it configures the library
as the root project. Add -Wextra, which the test flags lack.
The block sits before the first target, so the options reach shared_libs
and the step-by-step subdirectories too.
Three latent defects came out, two of them only under one compiler:
- A dead `double s` in both matrix examples (-Wunused-variable, in
-Wall, invisible only because the examples had no flags), left over
from a main() that exercised the scalar overloads. Rather than drop
the variable, call the methods the examples declare: matrix * matrix
(the dense/diagonal catch-all and the diagonal/diagonal override),
scalar * matrix, and matrix * scalar. The examples now demonstrate
the multiple dispatch they set up.
- Three `expr` bindings shadowing one another along the dynamic_cast
chain in slides.cpp (MSVC C4456; GCC and clang want -Wshadow, which
is in neither -Wall nor -Wextra). Named for the type each one casts
to, which reads better anyway.
- GCC 16 reports -Wsfinae-incomplete on the friendship examples, which
name virtual_ptr<Cat> in a friend declaration inside Animal, before
Cat is defined - the point of the example. Defaulting the registry
argument runs the affinity probe, a SFINAE context. The library asks
the question again under its `rechecked` tag, where the class has to
be complete, and refuses an answer that has changed, so the warning
is kept visible but non-fatal. It is on by default - neither -Wall
nor -Wextra brings it in - so this is pre-existing, and already in
the reflection job's log; only -Werror makes it fatal. Probed rather
than tied to a version: only GCC 16 knows the option, and naming it
on GCC 13, GCC 15 or clang is a hard error.
Verified on GCC 13 (Release), GCC 16 with -freflection (the reflection
job's configuration, Debug + shared libs, 203/203 tests), clang 22, and
MSVC v18 /W4 /WX over all 31 examples. /we4265, which the test flags also
carry, is left off: it fires in preamble.hpp, not in the examples.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Eo4q4cYTx457W7oaunqsQ
jll63
force-pushed
the
fix/custom-rtti-example-ids
branch
from
October 10, 2026 17:06
2fcee3b to
997e6aa
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #129 +/- ##
========================================
Coverage 92.34% 92.34%
========================================
Files 27 27
Lines 2234 2234
Branches 679 677 -2
========================================
Hits 2063 2063
Misses 112 112
Partials 59 59 Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
(Written by Claude Code, on behalf of @jll63.)
Both
custom_rttiexamples returnreinterpret_cast<type_id>(0)for every type that does not derive fromNode:That reads as harmless, since such types never take part in dispatch. But
static_typeis also how a method is identified, and amethod<...>specialization is not derived fromNode, so it takes that branch.augment_methodskeysmethod_maponrtti::type_index(method_type_id), so every method in the registry lands under the same key: they merge into one logical method, their overriders pool together, no overrider dominates, and the first call reachesfn_ambiguous. Neither registry has anerror_handleroroutputpolicy, so the program aborts with no message.The arity assertion in
augment_methodsdoes not catch it — it only fires when the merged copies disagree on arity, and then only in a debug build.Why it is invisible today
Each example declares exactly one method, so nothing merges and both run correctly. The defect bites the reader who follows the page and adds a second method to their own registry, which is the natural next step — and the failure gives them nothing to go on.
Demonstration
Adding a
depthmethod to each example, changing nothing else:Aborted (core dumped), exit 1342 3 + 4 * = 20 depth=3, exit 0Aborted (core dumped), exit 13420 depth=3, exit 0The fix
Non-polymorphic types get the address of a function-local static — what the library's own
static_rttipolicy does — anddynamic_typedelegates tostatic_typeso the two cannot disagree.The page gains a paragraph explaining why the shared placeholder is a trap, and the sentence promising a "small, dense range" of type ids is narrowed to the classes that take part in dispatch, which is what
vptr_vectorindexes.Scope
Every other custom
static_typein the tree already gives non-polymorphic types distinct ids: thestatic_rttiandnamed_static_rttipolicies, and the five tests that define one (test_custom_rtti_simple,_deferred,_virtual_base,_simple_projection,test_initialize_dropped_class). Only the examples were wrong, which is why no test caught it.Warning flags on the examples build
The unused
std::ostream¶meter that the second commit removes was only noticed by eye, which prompted the question of what does check these files. The answer was nothing: there is no Jamfile underdoc/modules/ROOT/examples, so b2 never compiles the examples, and the CMake build — their only check — was passing them no warning flags at all.doc/modules/ROOT/examples/CMakeLists.txtnow mirrorstest/CMakeLists.txt: the flags go on underBOOST_OPENMETHOD_WARNINGS_AS_ERRORS, as-Wall -Wextra -Werroror/W4 /WX, set before the first target so they also reachshared_libsand the step-by-step subdirectories.-Wextrais more than the test flags carry.This is enforced in CI rather than locally only: C++26 reflection is the sole CMake job in
ci.yml, it setsWARNINGS_AS_ERRORS=ON, and it configures the library as the root project — which defaultsBOOST_OPENMETHOD_BUILD_EXAMPLEStoON.Three latent defects came out, two of them visible to only one compiler:
A dead
double sin both matrix examples, left over from amainthat exercised the scalar overloads. Plain-Wunused-variable, from-Wall— invisible purely because the examples had no flags. Rather than drop the variable, the examples now call the methods they declare:matrix * matrix(the dense/diagonal catch-all and the diagonal/diagonal override),scalar * matrixandmatrix * scalar. They demonstrate the multiple dispatch they set up, which they previously did not.Three
exprbindings shadowing one another along thedynamic_castchain inslides.cpp. MSVC C4456; GCC and clang need-Wshadow, which is in neither-Wallnor-Wextra. Each is now named for the type it casts to, which reads better regardless.GCC 16 reports
-Wsfinae-incompleteon the friendship examples. They namevirtual_ptr<Cat>in a friend declaration insideAnimal, beforeCatis defined — which is the point of the example. Defaulting the registry argument runs the affinity probe, a SFINAE context, so GCC reports that the answer may change onceCatis complete. The library asks the question again under itsrecheckedtag, where the class has to be complete, and refuses an answer that has changed.This warning is pre-existing: it is on by default, brought in by neither
-Wallnor-Wextra, so it is already in the reflection job's log today and only-Werrormakes it fatal. It is kept visible but non-fatal with-Wno-error=sfinae-incomplete, behind acheck_cxx_compiler_flagprobe — GCC 13, GCC 15 and clang 22 all reject that option outright, so a version guess would have broken them./we4265, which the test flags also carry, is deliberately left off: it fires 29 times inpreamble.hppondetail::deferred_overrider_info, not in example code. That is a separate question, worth its own look since the tests do enable it.Verification
BUILD_EXAMPLES=ON,WARNINGS_AS_ERRORS=ON-std=c++26 -freflection, Debug,BUILD_SHARED_LIBS=ON-Wall -Wextra -Werrorover all 31 examples/W4 /WXover all 31 examplesPlus the Antora render for the doc commits — the two new
cpp:cross-references resolve to real reference pages.🤖 Generated with Claude Code
https://claude.ai/code/session_011Eo4q4cYTx457W7oaunqsQ