-
Notifications
You must be signed in to change notification settings - Fork 7
CWG2906 [expr.cond], [expr.const] Lvalue-to-rvalue conversion of class types disqualifies constant expressions #550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Note: lvalue-to-rvalue conversions of class types also occur in https://eel.is/c++draft/expr.call#11 |
#215 is related. Note that implementations also accept this example: struct S {
S() = default;
template<class = void>
constexpr S(const volatile S&) noexcept {}
template<class = void>
constexpr S(const volatile S&&) noexcept {}
};
constexpr volatile S s_volatile{};
constexpr auto s_copy = []{ return s_volatile; }(); It seems that we should restrict [expr.const] p5.9 to scalar types other than cv
Moreover, [expr.const] p5.11 seemingly imposes unintend restrictions on empty classes and cv
|
Carving out an exception for nullptr is fine; we should never attempt to access the "object" (possibly with indeterminate or erroneous value) stored in a variable of type nullptr_t. I would prefer reducing lvalue-to-rvalue conversions of class type. For the "volatile" example, could you please point to the place where we do the lvalue-to-rvalue conversion here? [stmt.return] expressly does a copy-initialization, not an lvalue-to-rvalue conversion, so I'm not seeing why we need to adjust [expr.const] for that. |
As pointed above, [expr.call] p11 requires the lvalue-to-rvalue conversion. struct S {
S() = default;
template<class = void>
constexpr S(const volatile S&) noexcept {}
template<class = void>
constexpr S(const volatile S&&) noexcept {}
};
constexpr volatile S s_volatile{};
constexpr bool varfun(...) { return true; }
static_assert(varfun(s_volatile)); This example is rejected by GCC and accepted by Clang. |
That was not your original example. For the "s_copy" example, you claimed lvalue-to-rvalue conversion was necessary. I was asking where/when that is prescribed. You've just changed the example to switch to [expr.call] p11, which is known-dodgy of sorts. |
Oh, I'm sorry that the original example was wrong for lvalue-to-rvalue conversion. I originally thought that it was equivalent to lvalue-to-rvalue conversion and the requirements were the same. |
See also #442 |
Reference (section label): [expr.cond], [expr.const]
Issue description
In some situations, the lvalue-to-rvalue conversion mandated by [expr.cond] paragraph 7 can apply to class types. Such lvalue-to-rvalue conversions may not be constant expressions (see [expr.const] paragraph 5, bullet 9) even though they result in a call to the copy constructor ([conv.lval] paragraph 3, bullet 2), and calling the copy constructor directly would be a constant expression.
None of MSVC, GCC, or Clang implement this behavior and permit
constexpr S d = false ? S{} : a;
instead.Suggested resolution
The use of lvalue-to-rvalue conversion in [expr.cond] may be eliminated for class types.
Alternatively, update [expr.const] to permit this case.
The text was updated successfully, but these errors were encountered: