https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124421
Bug ID: 124421
Summary: __builtin_constexpr_diag() feature request: method to
suppress context/stacktrace
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: ivan.lazaric.gcc at gmail dot com
Target Milestone: ---
`__builtin_constexpr_diag()` is a really useful tool for reporting detailed
issues to the user.
The fact it reports an error and continues execution is very useful,
as it allows the library author to easily give a more complete diagnostic to
the user.
Currently it has a downside though, it can be overly noisy.
Suppose we wrote some code that depends on all non-static data members being
public.
We can verify this to be true, an example of such code:
```
#include <meta>
struct S {
int x, y;
private:
int z, w;
};
consteval void validate(std::meta::info type) {
auto ctx = std::meta::access_context::unchecked();
auto members = nonstatic_data_members_of(type, ctx);
for (auto member : members)
if (!is_public(member)) {
auto msg = std::string("member is not public: ") +
display_string_of(member);
__builtin_constexpr_diag(2, "validation", std::string_view(msg));
}
}
consteval void intermediate() { validate(^^S); }
consteval void top_level() { intermediate(); }
consteval { top_level(); }
```
Compiling with just `-std=c++26 -freflection`
The diagnostics this code produces:
```
<source>:23:26: in 'constexpr' expansion of '<lambda()> static()'
23 | consteval { top_level(); }
| ^
<source>:23:22: in 'constexpr' expansion of 'top_level()'
23 | consteval { top_level(); }
| ~~~~~~~~~^~
<source>:21:42: in 'constexpr' expansion of 'intermediate()'
21 | consteval void top_level() { intermediate(); }
| ~~~~~~~~~~~~^~
<source>:19:41: in 'constexpr' expansion of 'validate(^^S)'
19 | consteval void intermediate() { validate(^^S); }
| ~~~~~~~~^~~~~
<source>:15:37: error: constexpr message: member is not public: S::z
[validation]
15 | __builtin_constexpr_diag(2, "validation",
std::string_view(msg));
|
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:23:26: in 'constexpr' expansion of '<lambda()> static()'
23 | consteval { top_level(); }
| ^
<source>:23:22: in 'constexpr' expansion of 'top_level()'
23 | consteval { top_level(); }
| ~~~~~~~~~^~
<source>:21:42: in 'constexpr' expansion of 'intermediate()'
21 | consteval void top_level() { intermediate(); }
| ~~~~~~~~~~~~^~
<source>:19:41: in 'constexpr' expansion of 'validate(^^S)'
19 | consteval void intermediate() { validate(^^S); }
| ~~~~~~~~^~~~~
<source>:15:37: error: constexpr message: member is not public: S::w
[validation]
15 | __builtin_constexpr_diag(2, "validation",
std::string_view(msg));
|
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
Of note here is the "constexpr stacktrace" is emitted twice, and is rather
visually noisy.
As such, I suggest implementing a method of suppressing the context/stacktrace
of `__builtin_constexpr_diag()`, perhaps by or-ing 32 into the first argument.
My opinion is this would make it significantly easier on library authors
to produce quality diagnostics.
I believe a common pattern would be to emit all errors with context suppressed,
and at end, if at least one error was hit, emit a generic error with context
enabled.
Potential shape of previous code diagnostics with such suppression (2 -> 34):
```
<source>:15:37: error: constexpr message: member is not public: S::z
[validation]
<source>:15:37: error: constexpr message: member is not public: S::w
[validation]
```
Godbolt of the example code: https://godbolt.org/z/865zxG11h