Skip to content

doc: stop the detail-hiding macro leaking into the rendered constraints - #92

Open
jll63 wants to merge 4 commits into
boostorg:developfrom
jll63:fix/mrdocs-detail-prefix
Open

doc: stop the detail-hiding macro leaking into the rendered constraints#92
jll63 wants to merge 4 commits into
boostorg:developfrom
jll63:fix/mrdocs-detail-prefix

Conversation

@jll63

@jll63 jll63 commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Seven reference pages leaked BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS into the rendered
requires-clause, e.g.

template<typename T>
requires !BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
                IsVirtualAny<std::decay_t<T>> && ...
virtual_any(T&& value);

This is cppalliance/mrdocs#1016. Upstream cannot fix it until MrDocs can manipulate expression
trees, so the workaround has to live in the headers.

Why it happens

MrDocs turns the condition of an enable_if_t used as a defaulted template argument into a
requires-clause by copying the raw source text spanning the condition expression. A macro
therefore disappears only when it sits before the expression's first token: it expands to
nothing under __MRDOCS__, so the copied range simply starts after it. Anywhere inside the
range - after a !, after a &&, inside parentheses - its name is copied verbatim.

That is the asymmetry noted on the issue: in a two-occurrence constraint the first macro is
outside the range and the second is inside it. The shape of the macro is irrelevant - object-like,
function-like, or a bare #ifndef __MRDOCS__ around detail:: all leak, and a macro that carries
the ! leaks too, because the expression then starts inside a macro expansion.

Two rules

  • The macro must be the first thing in the condition. Spell a negation Trait<T> == false, not
    !Trait<T>.
  • One trait per condition. When a constraint needs several, give each its own defaulted template
    parameter: MrDocs joins them with && in source order, so the rendered clause is unchanged.

Recorded next to the macro definition in core.hpp and in CLAUDE.md, since neither is
discoverable from the failure.

Changes

  • BOOST_OPENMETHOD_UNLESS_MRDOCS(...) replaces BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS,
    spelled BOOST_OPENMETHOD_UNLESS_MRDOCS(detail::) at the call sites. The macro now says what it
    does rather than encoding one payload in its name.
  • The four leaking constraints in virtual_ptr and virtual_any follow the rules above.
  • The three smart-pointer converting constructors no longer declare their template parameter
    list twice
    . They carried an unqualified copy under #ifdef __MRDOCS__ beside the real one;
    only MrDocs ever compiled the copy, so the two could drift apart silently and the reference would
    document a constraint the library does not have. The rendered clause is unchanged.
  • All five constrained members of the smart-pointer virtual_ptr now read
    SameSmartPtr && <constructible|assignable> && IsPolymorphic; the constructors previously
    ordered the conjuncts differently from the assignments.
  • doc/mrdocs.yml: exclude-macros matched the old name through BOOST_OPENMETHOD_DETAIL_*.
    BOOST_OPENMETHOD_*UNLESS_MRDOCS covers the new name and the two namespace macros, which had
    never been listed. (Checked that MrDocs honours a star in the middle of a pattern - these macros
    carry no doc comment, so a bad pattern would have failed silently.)

Splitting the conditions also makes substitution short-circuit, so typename Other::element_type
is only formed once SameSmartPtr has passed.

Verification

  • 154/154 tests pass.
  • Reference rebuilt with doc/build_antora.sh: grep -rl MRDOCS doc/html/ returns nothing, and
    the five smart-pointer synopses and the two virtual_any ones read as intended.
  • The remaining #ifdef __MRDOCS__ blocks were checked: they remove declarations from the
    reference (friends, deleted final_virtual_ptr overloads, the VirtualTraits blueprint) rather
    than restate them.

🤖 Generated with Claude Code

jll63 and others added 4 commits August 23, 2026 11:12
MrDocs renders the condition of an enable_if_t used as a defaulted template
argument as a C++20 requires-clause by copying the raw source text spanning the
condition expression - it does not walk the expression tree
(cppalliance/mrdocs#1016). BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS therefore
disappears only when it sits before the first token of the condition, where it
expands to nothing under __MRDOCS__ and so falls outside the copied range;
anywhere inside the condition its name is printed verbatim, whatever shape the
macro has. That is why a constraint naming two exposition-only traits rendered
the first correctly and leaked the second.

Two rules restore the reference, documented next to the macro definition and in
CLAUDE.md: the macro must lead the condition, with a negation spelled
`Trait<T> == false`; and each trait gets its own defaulted template parameter,
which MrDocs joins with && in source order, leaving the rendered clause
unchanged. Splitting also makes substitution short-circuit, so
`typename Other::element_type` is only formed once SameSmartPtr has passed.

No reference page mentions the macro any more.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…RDOCS(...)

Replace BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS with a function-like
BOOST_OPENMETHOD_UNLESS_MRDOCS(...), spelled at the call sites as
BOOST_OPENMETHOD_UNLESS_MRDOCS(detail::). The macro now says what it does -
drop this text under __MRDOCS__ - instead of encoding one payload in its name,
and the payload is visible where it is used.

The shape has no effect on the rendering: MrDocs copies the raw source text of
a constraint, so the macro still has to lead the condition, whether it is
object-like or function-like. The two rules recorded in the previous commit are
unchanged.

Also widen the mrdocs.yml exclude-macros pattern, which matched the old name
through 'BOOST_OPENMETHOD_DETAIL_*'. 'BOOST_OPENMETHOD_*UNLESS_MRDOCS' covers
the new name and the two namespace macros, which were never listed. Verified
that MrDocs honours a glob star in the middle of a pattern.

Document, in CLAUDE.md, that anything posted in public under the maintainer's
account has to identify Claude as its author on the first line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The three constructors taking a smart pointer to a derived class carried two
copies of their template parameter list: an unqualified one under
`#ifdef __MRDOCS__`, for the reference, and the real `detail::`-qualified one.
Only MrDocs ever compiles the first, so the two could drift apart without
anything failing, and the reference would document a constraint the library
does not have.

The rules recorded in the previous commits cover this case, so state each
constraint once, with SameSmartPtr and IsPolymorphic in a defaulted template
parameter each. The rendered requires-clause is byte-for-byte what the
duplicated declarations produced.

The `#ifdef __MRDOCS__` blocks that remain remove declarations from the
reference - friends, deleted overloads, the VirtualTraits blueprint - rather
than restate them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ments

The three converting constructors listed IsPolymorphic before the
constructibility test, the two converting assignments after it. Put the
exposition-only traits at the ends in all five, so the rendered clause reads
SameSmartPtr && <constructible|assignable> && IsPolymorphic throughout, and the
five template parameter lists are spelled and formatted identically.

Substitution still short-circuits on SameSmartPtr, so `typename
Other::element_type` is only formed for an actual smart pointer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jll63
jll63 force-pushed the fix/mrdocs-detail-prefix branch from 541a67d to 752b3eb Compare August 23, 2026 15:12
@jll63 jll63 changed the title doc: stop the detail-hiding macro leaking into the rendered constraints doc: misc improvements Aug 23, 2026
@jll63 jll63 changed the title doc: misc improvements doc: stop the detail-hiding macro leaking into the rendered constraints Aug 23, 2026
@cppalliance-bot

Copy link
Copy Markdown

An automated preview of the documentation is available at https://92.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-08-23 15:16:09 UTC

@codecov

codecov Bot commented Aug 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.97%. Comparing base (725d5fd) to head (752b3eb).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop      #92   +/-   ##
========================================
  Coverage    94.97%   94.97%           
========================================
  Files           99       99           
  Lines         4322     4322           
  Branches      2138     2138           
========================================
  Hits          4105     4105           
  Misses         160      160           
  Partials        57       57           
Files with missing lines Coverage Δ
include/boost/openmethod/core.hpp 93.06% <ø> (ø)
include/boost/openmethod/interop/virtual_any.hpp 100.00% <ø> (ø)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 725d5fd...752b3eb. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants