C++ Logo

sg15

Advanced search

Re: [isocpp-sg15] [P2758] Emitting messages at compile time

From: Aaron Ballman <aaron_at_[hidden]>
Date: Wed, 16 Oct 2024 09:40:27 -0400
On Wed, Oct 16, 2024 at 6:10 AM Jonathan Wakely <cxx_at_[hidden]> wrote:
>
>
>
> On Tue, 15 Oct 2024 at 18:53, Aaron Ballman via SG15 <sg15_at_[hidden]> wrote:
>>
>> Thanks! FWIW, users do want this sort of capability, but the fact that
>> no implementation has yet to add a feature with bells and whistles is
>> because the problem is not easy to solve. I'm highly skeptical that
>> this is something WG21 should be standardizing at all currently; it's
>> firmly in the realm of QoI and different implementations have
>> different needs (and our needs evolve over time). The only form of the
>> feature I would consider supporting would be one that accepts the
>> message to be printed during constant evaluation and nothing else.
>> Anything with more bells and whistles will be problematic in practice.
>>
>> Practical implementability problems include:
>> * Different implementations have different severities for diagnostics
>> (error, warning, note, remark, no severity distinctions, etc)
>
>
> We already have a distinction between #error and #warning, how is this any different?
> constexpr_print just outputs a message at compile time (which you've said is fine).

Because it adds another layer of distinction (constexpr_print_str)
which may or may not make sense to any given implementation. In Clang
specifically, is that a note or a remark? (There are problems with
whichever one we pick, so it'd probably be an entirely new thing, but
none of our users have actually asked for something like that, at
least that I'm aware of.)

> constexpr_warning outputs a diagnostic message with similar behaviour to #warning. If the implementation can't do non-fatal diagnostic messages, i.e. warnings as opposed to errors, then presumably that's already a problem for #warning. The behaviour for constexpr_warning can be consistent with that.

This alone is fine for us, except it comes with a tag which is problematic.

> constexpr_error outputs a diagnostic message with similar behaviour to #error, rendering the program ill-formed.

This alone is (generally) fine for us.

>> * Different implementations have different rules for additional
>> effects on diagnostics (default ignore, default error, SFINAE trap,
>> etc)
>
> I don't think I understand this point.

When discussing adding a similar feature to Clang, the points always
raised are 1) I want to pick the diagnostic name and grouping for
this, 2) I have a special case that I know the compiler supports
because there's a diagnostic I can point to which does the thing I
want. Real-world use cases for this functionality will naturally want
to have the same power as what the compiler already provides, but that
isn't something that can be easily standardized due to the differences
across implementations. We could perhaps figure out some
implementation-defined "options" object that lets the implementation
expose any extra options to the diagnostic they want.

I realize the paper isn't proposing anything nearly this complicated,
but my point is: if we start down the road of providing more than what
`#error` or `#warning` can do in terms of "tags", there will be a
natural pressure on the committee and implementers to go further. I'd
rather see us skip the "tag" or design the feature so it can be
extended by implementations however they see fit.

>> * Different implementations have different ways to identify
>> diagnostics (unique numeric identifier, warning group, no
>> identification at all, etc)
>>
>> * Some implementations have the ability to group diagnostics together,
>> other implementations don't
>
> Those with a unique identifier could give a single ID to all constexpr_warning diagnostics, and they would all be disabled or all enabled together. That would be conforming (the grouping and suppression are only recommended practice).
> Those with no grouping could do something similar, with a -Wno-constexpr-warnings that affects them all. That would be conforming.

Those with no grouping support should introduce grouping for one
particular class of diagnostics?

Based on past discussions in Clang about this, our users would most
likely expect the tag to correspond to a warning group so they could
do `-Wno-user-specified-tag` which is probably also under some
umbrella to disable all user-specified diagnostics. However, we
diagnose unknown diagnostic groups from the driver
(https://godbolt.org/z/q4fb15e1q), so if there are now diagnostic
groups that we won't know about until constant expression evaluation
time we would struggle to support letting the user place diagnostics
under a user-specified warning group (beyond the umbrella).

> Implementations that want to give better user experiences could have options that use the tag-str to be more fine-grained. But it wouldn't be required for conformance.
>
> "Some implementations could not implement the Recommended practice" is fine, that's how normative encouragement is supposed to work.

Sure, is that really what the committee wants to aim for though?

Also keep in mind that there are more implementations than just
compilers. Static analysis tools also have way different functionality
in terms of how and what they present as diagnostics. (The point I'm
getting at is: there's a reason the standard traditionally has not
strayed into the realm of diagnostics any farther than #error and
#warning -- those are pretty ubiquitous, anything beyond that such as
suggested tags or groupings quickly runs afoul of all the various
implementation differences. Those differences are what distinguish the
implementations and are sometimes the primary driver of sales for the
tool, hence can be *very important* to leave up to QoI.)

>> * Some implementations localize their diagnostics, so trying to make
>> user-defined diagnostics look like compiler diagnostics can cause
>> consistency issues
>
> Isn't that already the case for static_assert messages? Would this be worse? Couldn't we cope?

It is already the case, this is only incrementally worse.

>> * Not all diagnostics are emitted to a terminal (there may be
>> limitations on what can be emitted as a diagnostic depending on
>> whether the diagnostics are being emitted to a terminal, to a list box
>> UI, to a SARIF file, etc)
>
>
> Isn't that also already the case for static_assert messages?
>
> If I do static_assert(false, "{ lol: { \"wat [ "); then the compiler already needs to be able to output that as SARIF without producing corrupted JSON.

True!

To be clear, what I'd prefer to see is: 1) drop the
constexpr_print_str function as it doesn't cleanly map across
implementations, 2) drop the tag from the interfaces. Alternatively
for #2, instead of having a tag, have implementation-defined structs
for use with constexpr_warning_str and constexpr_error_str that allow
the implementation to specify whatever options they're comfortable
supporting.

~Aaron

>> These sorts of things are why I only support a very simple
>> standardized interface, if anything. Trying to standardize something
>> with more bells and whistles will run into problems where not every
>> implementation can support it or will be willing to change their
>> diagnostic practices to support it.
>>
>> ~Aaron
>>
>> On Mon, Oct 14, 2024 at 4:05 PM Barry Revzin via SG15
>> <sg15_at_[hidden]> wrote:
>> >
>> > Hey Tooling Study Group,
>> >
>> > I have this paper, P2758 (latest currently: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2758r3.html), which proposes low-level utilities for emitting messages during constant evaluation time.
>> >
>> > Those messages have three kinds (print, warning, and error) and can also be tagged. The intent of the tagging is to give the user the kind of control typically reserved for the compiler. That is, the format library can diagnose something with:
>> >
>> > std::constexpr_warning("format-too-many-args", "Format string consumed {} arguments but {} were provided.", current_arg, total);
>> >
>> > And that'll emit a compiler warning that maybe can be explicitly enabled (with some flag like -Wformat-too-many-args) or disabled (with some flag like -Wno-format-too-many-args). And possibly likewise with #pragmas for local blocks. Of course the actual mechanism is implementation-defined and it's likely the flags won't be exactly that so that they won't clash with actual implementation warnings.
>> >
>> > Evolution was happy with this proposal, but wanted you all to take a look at it for its use of tagging to make sure that this is a viable path. Right now, the paper's restriction on tagging is that it only contains, basically, a-z, A-Z, 0-9, an underscore, or a hyphen — although it presently also allows empty strings, which I'll change in a subsequent revision. That restriction avoids having to really deal with unicode stuff, while also matching the set of characters currently used in compiler flags anyway, so doesn't seem like it's cutting off anything useful to me.
>> >
>> > Thanks in advance for the feedback,
>> >
>> > Barry
>> > _______________________________________________
>> > SG15 mailing list
>> > SG15_at_[hidden]
>> > https://lists.isocpp.org/mailman/listinfo.cgi/sg15
>> _______________________________________________
>> SG15 mailing list
>> SG15_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/sg15

Received on 2024-10-16 13:40:43