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 11:04:11 -0400
On Wed, Oct 16, 2024 at 9:56 AM Jonathan Wakely <cxx_at_[hidden]> wrote:
> On Wed, 16 Oct 2024 at 14:42, Aaron Ballman <aaron_at_[hidden]> wrote:
>>
>> 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?
>
>
> OK, they don't support disabling constexpr_warning diagnostics at all then. Sucks to be a user of that implementation, I guess.
>
>>
>>
>> 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
>
>
> I was imagining it would be -Wfoo=tag-str not -Wfoo-tag-str (where "foo" would be something like "user-specified" or "constexpr-print")
>
>>
>> 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).
>
>
> With what I imagined above, -Wuser-specified= would still be recognized, and you could ignore any tag-str argument to it. There's no unknown warning flag, just unrecognized arguments, but that's fine. The user says don't want warnings for the "acme-debug-dumps" tag-str? Fine ... if you don't get any such warnings during constant evaluation, they won't get them.

Yeah, there are different strategies we could use with different
tradeoffs. e.g., we may not be able to suggest corrections for
near-miss diagnostic arguments but that means we can more easily
handle unknown diagnostic arguments. (FWIW, Clang mostly doesn't
support warnings with arguments; we actually have to special-case
things like `-Wformat=2`; amusingly, the diagnostic group name itself
is `format=2` in Clang rather than handle the argument).

>> > 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?
>
>
> For implementations that absolutely *can't* do it, yes, that's why it's only a recommendation not a requirement.
>
> If none of the known implementations could follow the recommendation, that would be a problem. But I'm not aware of anything in this proposal that GCC couldn't implement here. I'd be surprised if Clang couldn't either. But it sounds like it's not a case of being unable, it's not wanting to because it opens unwanted cans of worms.

That's a fair way to put it -- we can support something along these
lines, but we'd definitely prefer to avoid opening the can of worms in
the first place.

~Aaron

>
>
>>
>>
>> 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 15:04:29