feat: render long noexcept specifications as noexcept(see-below)#1180
feat: render long noexcept specifications as noexcept(see-below)#1180gennaroprota wants to merge 1 commit into
Conversation
✨ Highlights
🧾 Changes by Scope
🔝 Top Files
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #1180 +/- ##
========================================
Coverage 82.12% 82.12%
========================================
Files 33 33
Lines 3149 3149
Branches 734 734
========================================
Hits 2586 2586
Misses 387 387
Partials 176 176
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
1e52e6d to
7ee2a4e
Compare
|
An automated preview of the documentation is available at https://1180.mrdocs.prtest2.cppalliance.org/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-05-14 09:09:01 UTC |
4fa1508 to
4b717a2
Compare
|
What criteria did we end up with to consider the condition long? |
|
There's no length check. The rule ended up being Non-dependent specifications do carry text but, in practice, that's empty or literally |
|
I'm not clear on what this means. OK. Questions:
For example, if I mean, to some extent, the strategy ended up being, in practice, "almost always use see-below". And it's mostly coherent with cppreference it uses see-below even for things like But I'm not sure this is a good thing for mrdocs because cppreference inherited this format from the old times when concepts weren't a thing (so the other rules were already there as a rule at the bottom of the page) and is edited manually (so they can always go back and forth and don't have to justify their thresholds precisely). On the other hand, for MrDocs, when we look at the nature of user complaints, it's usually only about the cases when it's not legible. This is typically when it's too large to render or when it uses lots of implementation details. In cases where it's something like What's interesting is if you look at https://en.cppreference.com/cpp/utility/expected/expected, you'll see the explicit specifications are actually inline when they're short. Their rule is not the same, and I assume it's because they don't have to maintain their own historical precedent in this case. |
|
OK, fixing an arbitrary length limit didn't look "right" to me, so I wanted something more logical and not arbitrary, like "dependent"/"non-dependent". But that's a weak proxy. If length is what users complain about (and we have that as |
|
Yes. That doesn't seem arbitrary at all. But please confirm what this looks like when rendered in adoc and html. |
139128a to
cc90113
Compare
cc90113 to
6ff8c77
Compare
| /** Whether an explicit-specifier was user-written. | ||
| */ | ||
| bool Implicit = true; | ||
| bool IsUserWritten = false; |
There was a problem hiding this comment.
Is this change really valuable? I think the other name came from Krystian, but I think it makes sense. Explicit/Implicit carries more semantic weight than UserWritten to me. Because the user chose to write what he chose to write anyway.
| /** Whether a noexcept-specifier was user-written. | ||
| */ | ||
| bool Implicit = true; | ||
| bool IsUserWritten = false; |
| `noexcept(see-below)` plus a separate specification section, | ||
| instead of inline in the signature. | ||
| */ | ||
| bool OperandIsLong = false; |
There was a problem hiding this comment.
Oh... This should be at the presentation level, not at this level in the handlebars templates. If we open this Pandora’s box, we can never close it again.
| </param> | ||
| <func-class>normal</func-class> | ||
| <noexcept> | ||
| <is-user-written>1</is-user-written> |
There was a problem hiding this comment.
It seems like we're not representing booleans correctly in XML.
| <func-class>normal</func-class> | ||
| <noexcept> | ||
| <is-user-written>1</is-user-written> | ||
| <kind>true</kind> |
There was a problem hiding this comment.
This also seems wrong.
There was a problem hiding this comment.
That's actually correct, although confusing, because NoexceptKind is defined as:
enum class NoexceptKind
{
/** Potentially-throwing exception specification
*/
False = 0,
/** Non-throwing exception specification
*/
True,
/** Dependent exception specification
*/
Dependent
};
| T&) noexcept(pass:q[_see-below_]); | ||
| ---- | ||
|
|
||
| === noexcept Specification |
There was a problem hiding this comment.
Is this intentional?
Should it be "noexcept specification"? Or maybe "noexcept Specification"? What does cppreference use?
There was a problem hiding this comment.
Cppreference puts everything under "Exceptions" (see e.g. https://en.cppreference.com/cpp/utility/expected/expected). In any case, MrDocs uses title case for section headings, so, if we keep that separate section, the title must say "Specification", with an uppercase "S".
6ff8c77 to
17a78f6
Compare
About this point, I noticed MrDocs supports lots of very nice C++ idioms that make life very convenient, and most of them are not documented. I'm noticing this as I'm working on this presentation about MrDocs. Maybe that's how this could go into the documentation. We could have a page or section for C++ idioms, and over time we can try to categorize them, and then we just have a reference of all the nice things MrDocs can do, and that's going to be one of them. |
MrDocs used to render the full `noexcept` operand inline, so a
declaration like
void swap(reference, reference) noexcept(
std::is_nothrow_move_constructible<value_t>::value &&
std::is_nothrow_move_assignable<value_t>::value &&
std::is_nothrow_move_constructible<json_value>::value &&
std::is_nothrow_move_assignable<json_value>::value);
buried the `noexcept` condition in a mostly-unreadable slop.
This replaces operands longer than 40 characters with an italic
"see-below" placeholder in the declaration, and moves the actual
condition to a dedicated "noexcept Specification" section of the
exposition:
void swap(reference, reference) noexcept(see-below);
=== noexcept Specification
noexcept when `...long condition...`.
The section is intentionally separate from the existing "Exceptions"
section, which continues to cover `@throws` documentation.
Closes issue cppalliance#1103.
17a78f6 to
d4b4a4f
Compare
MrDocs used to render the full
noexceptoperand inline, so a declaration likeburied the
noexceptcondition in a mostly-unreadable slop.This replaces dependent operands with an italic "see-below" placeholder in the declaration, and moves the actual condition to a dedicated "noexcept Specification" section of the exposition:
The section is intentionally separate from the existing "Exceptions" section, which continues to cover
@throwsdocumentation.Closes issue #1103.
[danger skip docs].
Summary
Renders long
noexceptspecifications asnoexcept(see-below)and pulls the actual condition into a dedicated "noexcept Specification" section of the exposition, so the function signature stays readable when the condition is a dependent expression. Closes #1103.Before this PR, a declaration like
buried the
noexceptkeyword in a wall of trait expressions. After this PR, the same declaration renders asand the condition appears under a separate "noexcept Specification" subsection alongside the declaration. The section is intentionally separate from the existing "Exceptions" section, which continues to cover
@throwsdocumentation.The implementation lives mostly in the Handlebars template layer. The C++ side adds a small helper surface in
include/mrdocs/Support/Handlebars.hpp(implemented insrc/lib/Support/Handlebars.cpp); the existing function-signature, declarator-suffix, and per-format symbol partials undershare/mrdocs/addons/are updated to consume it.Changes
src/lib/Support/Handlebars.cppand exposed via the publicinclude/mrdocs/Support/Handlebars.hpp(additive). Templates updated undershare/mrdocs/addons/:common/partials/symbol/signature/function.hbsandcommon/partials/type/declarator-suffix.hbsdecide when to print(see-below);adoc/partials/symbol.adoc.hbsandhtml/partials/symbol.html.hbsrender the new "noexcept Specification" section in their respective output formats.src/test/lib/Metadata/NoexceptInfo.cpp(118 lines) covers the underlying noexcept-info classification — which operands stay inline vs. get redirected to the see-below section.test-files/golden-tests/symbols/function/noexcept.{cpp,xml,html,adoc}fixture exercises the see-below path end-to-end across all three output formats.noexceptspecifications changes — downstream tooling that scrapes function signatures and expects the full inlined condition will need to also read the new "noexcept Specification" section.Testing
src/test/lib/Metadata/NoexceptInfo.cppis the unit-level coverage for the classification rule (when an operand is short enough to inline vs. long or dependent enough to redirect to the see-below section).test-files/golden-tests/symbols/function/noexcept.{cpp,xml,html,adoc}is the end-to-end coverage across all three output formats; any regression in either the classification or the template rendering will fail the golden output.Documentation
No user-facing documentation page is added (
[danger skip docs]). The change is a rendering improvement for generated output: it does not surface a new option, flag, or configuration knob a user would need to look up. The new "noexcept Specification" section is self-describing in the generated output.