Description
Full name of submitter (unless configured in github; will be published with the issue): Jim X
Consider this example
int main() {
std::nullptr_t np; // #1
constexpr void *p1 = np; // #2
}
According to [dcl.init.general] p12
If no initializer is specified for an object, the object is default-initialized.
[basic.types.general] p9
Arithmetic types ([basic.fundamental]), enumeration types, pointer types, pointer-to-member types ([basic.compound]), std::nullptr_t, and cv-qualified versions of these types are collectively called scalar types.
Hence, [dcl.init.general] p7.3 applies here
To default-initialize an object of type T means:
- [...]
- Otherwise, no initialization is performed.
So, the variable at #1
has no initialization. Then, at #2
, the full-expression of the initialization comprises: lvalue-to-rvalue conversion to np
([conv.lval]), and null pointer conversion([conv.ptr])
[conv.lval] p3 says
The result of the conversion is determined according to the following rules:
- If T is cv std::nullptr_t, the result is a null pointer constant ([conv.ptr]).
The lvalue-to-rvalue conversion to a glvalue of type cv std::nullptr_t
seems not to care whether the the glvalue is initialized. However, [basic.indet] says
When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced ([expr.ass]).
If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases
Moreover, np
is not usable in constant expressions according to [expr.const] p2, [expr.const] p3, and [expr.const] p4. So, the evaluation of the full-expression of the initialization at least violates
[expr.const] p5
an operation that would have undefined behavior as specified in [intro] through [cpp], excluding [dcl.attr.assume];
an lvalue-to-rvalue conversion unless it is applied to
- a non-volatile glvalue that refers to an object that is usable in constant expressions, or
However, GCC and Clang both accept this example, only msvc rejects it.
Suggested resolution
Anyway, [conv.lval] p3.1 implies that the result of lvalue-to-rvalue conversion to any glvlaue of type std::nullptr_t
(regardless of whether it is initialized or uninitialized), the result is always a null pointer constant.
[expr.const] p5.9 and [basic.indet] p2 should have the special specification for std::nullptr_t
.