Open Eisenwave opened 1 month ago
if constexpr
in non-dependent contexts has two special powers. The discarded statements don't odr-use entities (well, technically they do odr-use them, it's just that this odr-use doesn't require a definition), and don't participate in return type deduction. Instead of removing those special powers, we should just clarify that the definition affects the semantics in this case.
Add a paragraph after [temp.inst]/8:
The existence of a definition of a function is considered to affect the semantics of the program if the function is named by an expression ([basic.def.odr]) and its declared return type is a placeholder type ([dcl.spec.auto]).
@t3nsor what about the compiler divergence for -> void
? Clang would be wrong then if we preserved these properties outside of templates.
Even with insisting on instantiation of deduced return type functions, I think it would rustle a lot of people's jimmies if non-deduced lambdas weren't instantiated, and I'm not convinced we want to keep that behavior.
I think Clang just has a bug in the -> void
case, unless someone convinces me otherwise.
The current wording is clear that something like if constexpr(false) { f(0); }
doesn't require f
to have a definition anywhere in the program (in the non-deduced return type cases). I don't think we should be messing with that in CWG and breaking the code of anyone who relies on this. So if you want to force instantiation in the -> void
case then you should come up with some other specification technique to make it so. But I don't really see the point of spending effort on this (and you'll probably still break some people's code).
For the decltype(s.x)
case, you get a substitution failure, and overload resolution fails. We don't need any change to the wording to make it clear that it's ill-formed.
CWG2893
Reference: [stmt.if] p2
Link to reflector/Mattermost: https://lists.isocpp.org/core/2024/05/15848.php, https://chat.isocpp.org/general/pl/5gki63y36fd9m8wwk77qzofica
Issue Description
This program is well-formed because neither of the conditions (see [temp.inst] p5) for instantiating the call operator template of the generic lambda are met:
operator()<int>
is not needed because of odr-use in a discarded statement (see [basic.def.odr] p12), andHowever, MSVC, GCC, and Clang reject this program. Only Clang rejects it for a lambda with
-> void
return type. It would be burdensome for users and implementors if this program was well-formed.An instantiation might still be needed considering that the lambda can have a return type with a private destructor, or be
[[nodiscard]]
, although the rules are unclear for this.Suggested Resolution
In [smt.if] p2, re-define discarded statement to only apply within a templated entity: