Summary
The 104 @code blocks in our public headers are never compiled by anything. They
are the only code we publish with no build gate. This issue proposes extracting
every block from the MrDocs corpus, generating one translation unit per block, and
compiling and linking them in CI with the same warnings-as-errors posture as
test/doc/snippets.
Measured baseline (method below): 73 of the 104 blocks do not compile.
There is a prerequisite: MrDocs currently aborts on our corpus. It is fully
diagnosed in Prerequisite: fix the MrDocs abort
and must be resolved first.
Why we implement this ourselves
MrDocs does not have a code-block extraction feature. It is an open,
unimplemented request: cppalliance/mrdocs#620 "Compile code snippets in
javadocs", filed 2024-06-05,
label feat, no milestone, no PR. Its only substance is a Dec 2025 comment noting
that rustdoc "generate[s] a single long file containing all examples".
Verified against both cached 0.8.0 builds and current develop: no CLI option, no
config key, and no generator does this.
We do not need it. The data is already exposed. mrdocs::doc::CodeBlock carries
{ literal, info }, and the XML generator emits each block verbatim:
<code><kind>code</kind><literal>poc::widget w;
w.spin();</literal></code>
A ~40-line extractor over reference.xml suffices. Proven with a throwaway PoC: a
header with 5 blocks (one valid, one with a typo'd member, one @code{.bash}, one
declaration fragment) extracted cleanly, compiled 4, skipped the shell block, and
failed the broken one with exit 1.
What we already do, and the gap
test/doc/ is the precedent, and it is stronger than the docstring situation:
| corpus |
count |
built |
linked |
run |
warnings |
test/doc/snippets/*.cpp |
40 |
yes |
yes |
yes — 35 declare TEST_SUITE(...), run under b2 (run [ glob snippets/*.cpp ]) and ctest (boost_capy_test_suite_discover_tests) |
-Wall -Wextra -Werror / /W4 /WX |
test/doc/programs/*.cpp |
25 |
yes |
yes |
yes — one executable each, passes when it exits cleanly; 3b_synchronization_race is compile-only |
same |
docstring @code blocks |
104 |
no |
no |
no |
none |
Doc snippets build, link, and run. Docstring blocks get nothing.
Docstring blocks should build and link, but not run, matching what
test/doc/snippets does minus execution. Running needs a main, an io_context
and real I/O, and the blocks have no expected output to assert against. Linking, by
contrast, is nearly free and catches a class of error compilation cannot: calling
API that has a declaration but no definition.
Measured on the blocks that compile today: 30 of 31 link against
libboost_capy.a with a trivial main. The single failure is
ex/io_awaitable_promise_base.hpp:49, which illustrates a promise type whose
members (initial_suspend, final_suspend, get_return_object) are declared but
never defined — an incomplete example that the rewrite should complete anyway.
One binary per block. Blocks cannot share a link target: the 31 objects produce
5 duplicate-symbol collisions, all on example(), because independently authored
blocks pick the same names. This differs from test/doc/snippets, whose 40 files
are hand-authored into one binary with names managed by their authors.
Compile to an object with -c (never -fsyntax-only) so template instantiation and
constexpr evaluation are exercised, then link each object with a stub main.
Design
Requirement: every @code block must be valid at namespace scope. This adds
overhead to examples but makes every block trivially compilable, with no wrapping
heuristics guessing at intent.
Generated TU per block:
#include <boost/capy.hpp>
// the same -Wunused-* suppression preamble test/doc/snippets/*.cpp already carry
namespace capy = boost::capy; // 5 blocks write `capy::` unqualified
using namespace boost::capy; // or boost::capy::test for test/ headers
<block literal verbatim>
The using namespace is not optional. Docstring blocks are written from inside the
library's namespace — they say task<>, fuse, mutable_buffer. Without a
using-directive 0 of 104 blocks compile, and every failure is
no template named 'task'-style lookup noise that says nothing about block
quality. MrDocs knows each symbol's enclosing namespace, so the harness can emit
the correct directive per block.
Suggested layout, mirroring test/doc: generated files under a build directory,
compiled by a test/doc/docstrings target with boost_capy_doc_warnings_as_errors
applied, added to the tests target but registering no ctest entries.
Measured baseline
All 104 blocks extracted and compiled with the harness above
(clang++ -std=c++20 -c -Wall -Wextra -Werror):
|
count |
total @code blocks (52 headers) |
104 |
| compile today |
31 |
| require rewriting |
73 |
| failures that are warning-only |
0 |
Allowing four harness shapes (umbrella vs. declaring header, using-directive vs.
wrapping in namespace boost::capy { }) raises the pass count only to 36, so
harness generosity is not the lever — the blocks genuinely need rewriting.
Corpus characterisation:
| property |
count |
| contain a function or class definition |
89 |
bare co_await / co_return not inside a definition |
20 |
contain ... elision, i.e. pseudo-code that cannot compile |
15 |
tagged fences (@code{...}) |
0 |
The 15 elided blocks are in scope: they get upgraded to real, compiling code
rather than opted out.
The dominant failure is expected unqualified-id — the block is a bare statement
sequence. test/fuse.hpp opens with:
fuse()([](fuse& f) {
auto ec = f.maybe_fail();
...
});
fuse resolves correctly; the statement is simply not valid at namespace scope.
Under the new rule these become named functions.
Blocks requiring rewrite
| header |
blocks |
lines |
include/boost/capy/buffers.hpp |
1 |
383 |
include/boost/capy/buffers/buffer_slice.hpp |
1 |
63 |
include/boost/capy/buffers/consuming_buffers.hpp |
1 |
38 |
include/boost/capy/concept/execution_context.hpp |
1 |
51 |
include/boost/capy/concept/executor.hpp |
1 |
90 |
include/boost/capy/concept/io_awaitable.hpp |
2 |
81, 96 |
include/boost/capy/concept/io_runnable.hpp |
1 |
84 |
include/boost/capy/cond.hpp |
1 |
29 |
include/boost/capy/detail/thread_local_ptr.hpp |
1 |
42 |
include/boost/capy/ex/any_executor.hpp |
1 |
75 |
include/boost/capy/ex/async_event.hpp |
1 |
84 |
include/boost/capy/ex/async_waker.hpp |
1 |
103 |
include/boost/capy/ex/execution_context.hpp |
1 |
54 |
include/boost/capy/ex/executor_ref.hpp |
1 |
98 |
include/boost/capy/ex/immediate.hpp |
2 |
139, 214 |
include/boost/capy/ex/io_awaitable_promise_base.hpp |
1 |
105 |
include/boost/capy/ex/recycling_memory_resource.hpp |
1 |
42 |
include/boost/capy/ex/run.hpp |
2 |
614, 715 |
include/boost/capy/ex/run_async.hpp |
5 |
376, 541, 579, 627, 677 |
include/boost/capy/ex/strand.hpp |
1 |
72 |
include/boost/capy/ex/thread_pool.hpp |
1 |
37 |
include/boost/capy/ex/work_guard.hpp |
1 |
48 |
include/boost/capy/io/any_read_stream.hpp |
1 |
65 |
include/boost/capy/io/any_stream.hpp |
1 |
55 |
include/boost/capy/io/any_write_stream.hpp |
1 |
66 |
include/boost/capy/io/write_now.hpp |
2 |
66, 312 |
include/boost/capy/io_result.hpp |
2 |
33, 40 |
include/boost/capy/io_task.hpp |
1 |
27 |
include/boost/capy/task.hpp |
1 |
109 |
include/boost/capy/test/buffer_to_string.hpp |
1 |
30 |
include/boost/capy/test/bufgrind.hpp |
3 |
48, 67, 80 |
include/boost/capy/test/fuse.hpp |
20 |
75, 89, 99, 115, 145, 158, 176, 252, 293, 325, 361, 378, 423, 467, 607, 725, 784, 833, 889, 954 |
include/boost/capy/test/read_stream.hpp |
1 |
45 |
include/boost/capy/test/run_blocking.hpp |
4 |
297, 404, 437, 472 |
include/boost/capy/test/stream.hpp |
1 |
63 |
include/boost/capy/test/write_stream.hpp |
1 |
47 |
include/boost/capy/when_all.hpp |
2 |
621, 744 |
include/boost/capy/when_any.hpp |
2 |
698, 829 |
Corpus fidelity: three traps in the XML
Measured against the real capy corpus (reference.xml, 1745 declarations):
1. Filter inline code spans. The corpus contains 1891 <code> elements, but
only 111 are code blocks. The other 1780 are inline code spans, which carry
no <literal> child. Selecting on tag name alone inflates the work ~17x and feeds
garbage to the compiler. Select only <code> elements having a non-empty
<literal>.
2. Deduplicate by literal. Those 111 block instances reduce to 102 distinct
literals. Overload sets and copied documentation repeat the same block on several
symbols — 8 literals appear on more than one symbol, up to 3x. Without dedup the
same failure is reported repeatedly, attributed to different headers.
3. The corpus does not contain every block in the headers — this gate can
silently under-report. One of the 104 source blocks never reaches the corpus:
include/boost/capy/io/write_now.hpp:312 documents an operator() guarded by
#if BOOST_CAPY_WRITE_NOW_WORKAROUND (declared at line 330).
- That macro is
1 only for defined(__GNUC__) && !defined(__clang__).
- MrDocs uses clang, so the declaration is preprocessed away, the docstring
attaches to no symbol, and the block vanishes.
So coverage is compiler-dependent. The gate must cross-check the number of blocks
extracted from the corpus against a direct scan of the headers and fail on any
delta, otherwise blocks behind inactive preprocessor branches are skipped while
the gate reports green. Do not accept a green run as proof of coverage; verify the
gate by making it fail.
MrDocs limitations to work around
1. @code{.cpp} is broken — worse than mrdocs#244 records. CodeBlock::info is declared but
never populated anywhere in current develop; visitVerbatimBlock sets only
literal. The tag leaks into the literal and the remaining lines lose dedenting:
| fence |
emitted literal |
@code |
poc::widget w;\nw.spin(); — dedented correctly |
@code{.cpp} |
{.cpp}\n poc::widget w;\n w.spinn(); — tag leaks, indent kept |
We use zero tagged fences, so nothing regresses today. Since all blocks must
compile, no language tag is needed. Worth reporting upstream separately, because
develop's own commands/blocks.adoc
instructs users to write @code{.cpp}.
2. No per-block source location. Confirmed on the real corpus: no <code>
element carries a <location>; only the enclosing symbol does. A failing block can
only be reported at its symbol's declaration line. In the PoC a block at header
line ~19 was reported as line 35. Emit a #line directive pointing at the symbol
and document the caveat, or re-find the block by scanning the header.
Prerequisite: fix the MrDocs abort
MrDocs currently aborts on capy's corpus, so no XML-driven gate can run. Fully
diagnosed below.
Symptom
mrdocs: clang/lib/AST/ExprClassification.cpp:72:
Cl clang::Expr::ClassifyImpl(ASTContext &, SourceLocation *) const:
Assertion `isPRValue()' failed.
Reproduces with both cached 0.8.0 builds (develop f942a24, master e9f847d),
with both the adoc and xml generators, and under three independent compilation
databases. It is therefore not generator-specific and not a stale-build artifact.
Root cause
capy's headers trip an LLVM assertion when compiled as C++26, and MrDocs
compiles at C++26 whenever the compile command carries no explicit -std=.
Minimal repro — a one-line TU:
#include <boost/capy.hpp>
-std= in the compile-db entry |
result |
-std=c++17 |
no crash |
-std=c++20 |
no crash |
-std=c++23 |
no crash |
-std=gnu++23 |
no crash |
-std=c++26 |
CRASH |
-std=c++2c |
CRASH |
| (flag absent) |
CRASH — identical to C++26 |
Two independent paths reach a -std-less command:
-
The cmake: path, which is what the real doc build uses. MrDocs synthesizes
its own single-TU compilation database. The generated
.temp/build/compile_commands.json holds exactly one entry, for a generated
mrdocs.cpp containing:
#include <boost/capy.hpp>
#include <boost/capy/test.hpp>
and that entry has no -std= flag, despite doc/mrdocs.yml passing
-DCMAKE_CXX_STANDARD=20. The cmake: variable does not reach the synthesized
TU.
-
A real project compile database. Bisecting build_cmake/compile_commands.json
(170 entries) isolates extra/test_suite/test_suite.cpp, whose command is just
clang++ -I... -g -c test_suite.cpp. The cause is
extra/test_suite/CMakeLists.txt:21:
target_compile_features(boost_capy_test_suite PUBLIC cxx_std_17)
CMake satisfies a cxx_std_17 requirement with a compiler already defaulting to
C++17 by emitting no -std= flag at all.
What is ruled out
- Not a capy source defect. System clang compiles
test_suite.cpp with 0
errors at both its C++17 default and -std=c++26, and the umbrella header is
clean at C++20 and C++23.
- Not a stdlib incompatibility. Trivial headers including
<memory>,
<coroutine>, <tuple>, <optional>, <variant> and <functional> extract
fine.
- Not a stale build directory. Reproduces via the
cmake: path, which
configures its own fresh build tree.
- Not new headers. The mrdocs binaries are unchanged since June while
doc/build/site last built 2026-08-14, so the trigger is environmental.
Verified fix
Forcing -std=gnu++20 onto all 170 compile-database entries makes the whole run
succeed: rc=0, 1745 declarations extracted, a 3.0 MB reference.xml produced.
This was verified without editing any capy file, by rewriting the compilation
database.
The implementer needs to make MrDocs compile capy at C++20 through a supported
mechanism. Candidates, in rough order of preference:
Note that fixing only the CMake standard leaves the cmake: path broken, and
fixing only the cmake: path leaves the project-database route broken. Confirm
which path the doc build actually takes before declaring this resolved.
Acceptance criteria
Out of scope
- Running the linked binaries. They have no expected output, and running them
would need an io_context and real I/O. Linking is in scope; execution is not.
- Implementing mrdocs#620 upstream.
- The
@code{.cpp} language-tag fix (mrdocs#244) — track upstream.
Summary
The 104
@codeblocks in our public headers are never compiled by anything. Theyare the only code we publish with no build gate. This issue proposes extracting
every block from the MrDocs corpus, generating one translation unit per block, and
compiling and linking them in CI with the same warnings-as-errors posture as
test/doc/snippets.Measured baseline (method below): 73 of the 104 blocks do not compile.
There is a prerequisite: MrDocs currently aborts on our corpus. It is fully
diagnosed in Prerequisite: fix the MrDocs abort
and must be resolved first.
Why we implement this ourselves
MrDocs does not have a code-block extraction feature. It is an open,
unimplemented request: cppalliance/mrdocs#620 "Compile code snippets in
javadocs", filed 2024-06-05,
label
feat, no milestone, no PR. Its only substance is a Dec 2025 comment notingthat rustdoc "generate[s] a single long file containing all examples".
Verified against both cached 0.8.0 builds and current
develop: no CLI option, noconfig key, and no generator does this.
We do not need it. The data is already exposed.
mrdocs::doc::CodeBlockcarries{ literal, info }, and the XML generator emits each block verbatim:A ~40-line extractor over
reference.xmlsuffices. Proven with a throwaway PoC: aheader with 5 blocks (one valid, one with a typo'd member, one
@code{.bash}, onedeclaration fragment) extracted cleanly, compiled 4, skipped the shell block, and
failed the broken one with exit 1.
What we already do, and the gap
test/doc/is the precedent, and it is stronger than the docstring situation:test/doc/snippets/*.cppTEST_SUITE(...), run under b2 (run [ glob snippets/*.cpp ]) and ctest (boost_capy_test_suite_discover_tests)-Wall -Wextra -Werror//W4 /WXtest/doc/programs/*.cpp3b_synchronization_raceis compile-only@codeblocksDoc snippets build, link, and run. Docstring blocks get nothing.
Docstring blocks should build and link, but not run, matching what
test/doc/snippetsdoes minus execution. Running needs amain, anio_contextand real I/O, and the blocks have no expected output to assert against. Linking, by
contrast, is nearly free and catches a class of error compilation cannot: calling
API that has a declaration but no definition.
Measured on the blocks that compile today: 30 of 31 link against
libboost_capy.awith a trivialmain. The single failure isex/io_awaitable_promise_base.hpp:49, which illustrates a promise type whosemembers (
initial_suspend,final_suspend,get_return_object) are declared butnever defined — an incomplete example that the rewrite should complete anyway.
One binary per block. Blocks cannot share a link target: the 31 objects produce
5 duplicate-symbol collisions, all on
example(), because independently authoredblocks pick the same names. This differs from
test/doc/snippets, whose 40 filesare hand-authored into one binary with names managed by their authors.
Compile to an object with
-c(never-fsyntax-only) so template instantiation andconstexpr evaluation are exercised, then link each object with a stub
main.Design
Requirement: every
@codeblock must be valid at namespace scope. This addsoverhead to examples but makes every block trivially compilable, with no wrapping
heuristics guessing at intent.
Generated TU per block:
The
using namespaceis not optional. Docstring blocks are written from inside thelibrary's namespace — they say
task<>,fuse,mutable_buffer. Without ausing-directive 0 of 104 blocks compile, and every failure is
no template named 'task'-style lookup noise that says nothing about blockquality. MrDocs knows each symbol's enclosing namespace, so the harness can emit
the correct directive per block.
Suggested layout, mirroring
test/doc: generated files under a build directory,compiled by a
test/doc/docstringstarget withboost_capy_doc_warnings_as_errorsapplied, added to the
teststarget but registering no ctest entries.Measured baseline
All 104 blocks extracted and compiled with the harness above
(
clang++ -std=c++20 -c -Wall -Wextra -Werror):@codeblocks (52 headers)Allowing four harness shapes (umbrella vs. declaring header, using-directive vs.
wrapping in
namespace boost::capy { }) raises the pass count only to 36, soharness generosity is not the lever — the blocks genuinely need rewriting.
Corpus characterisation:
co_await/co_returnnot inside a definition...elision, i.e. pseudo-code that cannot compile@code{...})The 15 elided blocks are in scope: they get upgraded to real, compiling code
rather than opted out.
The dominant failure is
expected unqualified-id— the block is a bare statementsequence.
test/fuse.hppopens with:fuseresolves correctly; the statement is simply not valid at namespace scope.Under the new rule these become named functions.
Blocks requiring rewrite
include/boost/capy/buffers.hppinclude/boost/capy/buffers/buffer_slice.hppinclude/boost/capy/buffers/consuming_buffers.hppinclude/boost/capy/concept/execution_context.hppinclude/boost/capy/concept/executor.hppinclude/boost/capy/concept/io_awaitable.hppinclude/boost/capy/concept/io_runnable.hppinclude/boost/capy/cond.hppinclude/boost/capy/detail/thread_local_ptr.hppinclude/boost/capy/ex/any_executor.hppinclude/boost/capy/ex/async_event.hppinclude/boost/capy/ex/async_waker.hppinclude/boost/capy/ex/execution_context.hppinclude/boost/capy/ex/executor_ref.hppinclude/boost/capy/ex/immediate.hppinclude/boost/capy/ex/io_awaitable_promise_base.hppinclude/boost/capy/ex/recycling_memory_resource.hppinclude/boost/capy/ex/run.hppinclude/boost/capy/ex/run_async.hppinclude/boost/capy/ex/strand.hppinclude/boost/capy/ex/thread_pool.hppinclude/boost/capy/ex/work_guard.hppinclude/boost/capy/io/any_read_stream.hppinclude/boost/capy/io/any_stream.hppinclude/boost/capy/io/any_write_stream.hppinclude/boost/capy/io/write_now.hppinclude/boost/capy/io_result.hppinclude/boost/capy/io_task.hppinclude/boost/capy/task.hppinclude/boost/capy/test/buffer_to_string.hppinclude/boost/capy/test/bufgrind.hppinclude/boost/capy/test/fuse.hppinclude/boost/capy/test/read_stream.hppinclude/boost/capy/test/run_blocking.hppinclude/boost/capy/test/stream.hppinclude/boost/capy/test/write_stream.hppinclude/boost/capy/when_all.hppinclude/boost/capy/when_any.hppCorpus fidelity: three traps in the XML
Measured against the real capy corpus (
reference.xml, 1745 declarations):1. Filter inline code spans. The corpus contains 1891
<code>elements, butonly 111 are code blocks. The other 1780 are inline code spans, which carry
no
<literal>child. Selecting on tag name alone inflates the work ~17x and feedsgarbage to the compiler. Select only
<code>elements having a non-empty<literal>.2. Deduplicate by literal. Those 111 block instances reduce to 102 distinct
literals. Overload sets and copied documentation repeat the same block on several
symbols — 8 literals appear on more than one symbol, up to 3x. Without dedup the
same failure is reported repeatedly, attributed to different headers.
3. The corpus does not contain every block in the headers — this gate can
silently under-report. One of the 104 source blocks never reaches the corpus:
include/boost/capy/io/write_now.hpp:312documents anoperator()guarded by#if BOOST_CAPY_WRITE_NOW_WORKAROUND(declared at line 330).1only fordefined(__GNUC__) && !defined(__clang__).attaches to no symbol, and the block vanishes.
So coverage is compiler-dependent. The gate must cross-check the number of blocks
extracted from the corpus against a direct scan of the headers and fail on any
delta, otherwise blocks behind inactive preprocessor branches are skipped while
the gate reports green. Do not accept a green run as proof of coverage; verify the
gate by making it fail.
MrDocs limitations to work around
1.
@code{.cpp}is broken — worse than mrdocs#244 records.CodeBlock::infois declared butnever populated anywhere in current
develop;visitVerbatimBlocksets onlyliteral. The tag leaks into the literal and the remaining lines lose dedenting:literal@codepoc::widget w;\nw.spin();— dedented correctly@code{.cpp}{.cpp}\n poc::widget w;\n w.spinn();— tag leaks, indent keptWe use zero tagged fences, so nothing regresses today. Since all blocks must
compile, no language tag is needed. Worth reporting upstream separately, because
develop's own
commands/blocks.adocinstructs users to write
@code{.cpp}.2. No per-block source location. Confirmed on the real corpus: no
<code>element carries a
<location>; only the enclosing symbol does. A failing block canonly be reported at its symbol's declaration line. In the PoC a block at header
line ~19 was reported as line 35. Emit a
#linedirective pointing at the symboland document the caveat, or re-find the block by scanning the header.
Prerequisite: fix the MrDocs abort
MrDocs currently aborts on capy's corpus, so no XML-driven gate can run. Fully
diagnosed below.
Symptom
Reproduces with both cached 0.8.0 builds (
developf942a24,mastere9f847d),with both the
adocandxmlgenerators, and under three independent compilationdatabases. It is therefore not generator-specific and not a stale-build artifact.
Root cause
capy's headers trip an LLVM assertion when compiled as C++26, and MrDocs
compiles at C++26 whenever the compile command carries no explicit
-std=.Minimal repro — a one-line TU:
-std=in the compile-db entry-std=c++17-std=c++20-std=c++23-std=gnu++23-std=c++26-std=c++2cTwo independent paths reach a
-std-less command:The
cmake:path, which is what the real doc build uses. MrDocs synthesizesits own single-TU compilation database. The generated
.temp/build/compile_commands.jsonholds exactly one entry, for a generatedmrdocs.cppcontaining:and that entry has no
-std=flag, despitedoc/mrdocs.ymlpassing-DCMAKE_CXX_STANDARD=20. Thecmake:variable does not reach the synthesizedTU.
A real project compile database. Bisecting
build_cmake/compile_commands.json(170 entries) isolates
extra/test_suite/test_suite.cpp, whose command is justclang++ -I... -g -c test_suite.cpp. The cause isextra/test_suite/CMakeLists.txt:21:CMake satisfies a
cxx_std_17requirement with a compiler already defaulting toC++17 by emitting no
-std=flag at all.What is ruled out
test_suite.cppwith 0errors at both its C++17 default and
-std=c++26, and the umbrella header isclean at C++20 and C++23.
<memory>,<coroutine>,<tuple>,<optional>,<variant>and<functional>extractfine.
cmake:path, whichconfigures its own fresh build tree.
doc/build/sitelast built 2026-08-14, so the trigger is environmental.Verified fix
Forcing
-std=gnu++20onto all 170 compile-database entries makes the whole runsucceed: rc=0, 1745 declarations extracted, a 3.0 MB
reference.xmlproduced.This was verified without editing any capy file, by rewriting the compilation
database.
The implementer needs to make MrDocs compile capy at C++20 through a supported
mechanism. Candidates, in rough order of preference:
mrdocs.cppTU an explicit-std=c++20. Notedoc/mrdocs.ymlends itscmake:line with-DCMAKE_EXPORT_COMPILE_COMMANDS=OFF, overriding the=ONMrDocs passesitself — that looks unintentional and is likely why MrDocs falls back to
synthesizing its own TU instead of using the project database.
extra/test_suite/CMakeLists.txtfromcxx_std_17tocxx_std_20sothat entry carries a standard flag — both targets declare it, at lines 21
(
boost_capy_test_suite) and 29 (boost_capy_test_suite_main). Required ifthe project database is used; insufficient on its own, because the
cmake:path never reads it.
are valid C++26, so MrDocs should not abort — and defaulting to C++26 for a
C++20 library is itself questionable.
Note that fixing only the CMake standard leaves the
cmake:path broken, andfixing only the
cmake:path leaves the project-database route broken. Confirmwhich path the doc build actually takes before declaring this resolved.
Acceptance criteria
mrdocs --generator=xmlcompletes on capy.@codeblock ininclude/is valid at namespace scope, including the15 blocks currently using
...elision.<code>elements with a non-empty<literal>.and any delta fails the gate.
-Wall -Wextra -Werror(/W4 /WX) and each linksinto its own binary with a stub
main. The binaries are never executed.green run.
Out of scope
would need an
io_contextand real I/O. Linking is in scope; execution is not.@code{.cpp}language-tag fix (mrdocs#244) — track upstream.