Skip to content

CWG2907 [expr.const] uninitialized glvalue of type std::nullptr_t appears in the constant expression  #215

Closed
cplusplus/draft
#7458
@xmh0511

Description

@xmh0511

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions