Il 12/11/2024 17:21, Thiago Macieira via Std-Proposals ha scritto:
On Tuesday 12 November 2024 04:40:00 Pacific Standard Time Alberto Barbati via 
Std-Proposals wrote:
Hello everyone,

I'd like to know if there's interest in introducing a way to selectively
ignore the effects of the [[deprecated]] attribute. Such a thing could
be useful in at least two scenarios:

 1. You have an old API that is being replaced by a new API, but the new
    API is written in terms of the old one (either temporarily or
    because you plan to make the old API private in a future release,
    without completely removing it)
 2. You have both a “safe” and an “unsafe” API and you want to encourage
    the naïve user to use the safe one, while giving the possibility to
    an experienced user to choose the unsafe API by declaring such
    intent explicitly
3. Unit-testing the deprecated API itself.

This case is the most common occurrence for us by far in Qt. We want to test 
this API but at the same time we don't want to use other deprecated API around 
it. That means disabling all deprecation warnings is not a good idea. Leaving 
them all as warnings is also noisy.

That's a very good use case. Thanks for pointing that out.

We have a solution for this, which uses pragmas.
https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/
qcompilerdetection.h?h=v6.8.0#n1180

I have seen similar macros expanding to pragmas in several projects. For example the Unreal Engine has a macro PRAGMA_DISABLE_DEPRECATION_WARNINGS that is used 2500+ times in the entire codebase. I take that as a hint that a standardized attribute might be useful.

1) Are attributes the right tool?
I think so, because the code is syntactically correct.

2) Should we use a different attribute (as "deprecated_ignorable" above)
or can/should we overload the existing [[deprecated]]?
I don't think so. Either you have a reason to ignore a deprecation or you 
don't. The library author has already given you a heads up that this is either 
going away or is obsolete for some reason (or actively dangerous).
3) The example above uses a string literal to tag the deprecation, so
that it can be referenced in [[ignore_deprecation]]. Alternatives and
variations could be considered, including, but not limited to,
identifiers instead of strings, multiple tags, etc.
I think that is going too far. I'm not opposed to that, but in our experience, 
ignoring all deprecations for one statement or block suffices. You can always 
make shorter expressions that the ignoring should apply to and that's usually 
good code practice. Or use an IILE.

Ok, so no "fine grained" attribute. That's a good point.

4) Should [[ignore_deprecation]] be applied only to compount statements
(as in the example above) or other statements/entities? Are there scopes
that could use the attribute that we would be missing (for example
function default arguments)?
I'd like to see examples of where those would be useful and to see if there 
are other solutions to changing the content so it won't need the deprecated 
content in there.

For example, if you've deprecated a type, then just don't: deprecate the 
constructors instead. If you've deprecated a function that returns the default 
value for this function, add a wrapper.

What I was thinking is that we might want to handle these cases:

[[deprecated]] struct Type1
{
};

struct Type2
{
    [[deprecated]] Type2();
    Type2(int);
};

void f1(Type1 x);
Type1 f2();
void f3(Type2 x = {});

For f1 and f3 we might put the ignoring attribute in the parameter-declaration itself, but in the case of f2 I guess the only good place is on the entire declaration. In any case, this shows we might want to use the new attribute on other contexts beside statements and need to specify the scope in those cases. For example, if we decide to allow the attribute on the declaration, like this:

[ignore_deprecation]] Type1 f2()
{
    // what about here?
}

then we need to specify whether the attribute is active or not in the body of the function. The question is not moot, because we might also have:

[ignore_deprecation]] Type1 f2();

Type1 f2()
{
    // what about here?
}

Of course, the only solution is to write a paper :)

ab