Skip to content
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

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

Open
xmh0511 opened this issue Jan 10, 2023 · 6 comments

Comments

@xmh0511
Copy link

xmh0511 commented Jan 10, 2023

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.

@frederick-vs-ja
Copy link

I think we can just modify [expr.const] p5.9 as indicated:

  • (5.9.2) ... ; , or
  • (5.9.3) a glvalue of type cv std::nullptr_t;

I believe that [conv.lval] p3 already implies that lvalue-to-rvalue conversion to a glvalue of type cv std​::​nullptr_­t never produces an indeterminate value, so [basic.indet] p2 seems unrelated to me.

@xmh0511
Copy link
Author

xmh0511 commented Jan 23, 2023

I think we can just modify [expr.const] p5.9 as indicated:

  • (5.9.2) ... ; , or
  • (5.9.3) a glvalue of type cv std::nullptr_t;

I believe that [conv.lval] p3 already implies that lvalue-to-rvalue conversion to a glvalue of type cv std​::​nullptr_­t never produces an indeterminate value, so [basic.indet] p2 seems unrelated to me.

Yes, that's the suggested resolution.

so [basic.indet] p2 seems unrelated to me.

No, [basic.indet] uniformly applies all objects with automatic or dynamic storage duration that has no initialization performed. a gvalue of std::nullptr_t in this case does denote that object.

@jensmaurer
Copy link
Member

CWG2907

Since we never look at the value of a std::nullptr_t object, it's irrelevant whether its value is indeterminate or erroneous.

@jensmaurer jensmaurer changed the title [expr.const] uninitialized glvalue of type std::nullptr_t appears in the constant expression CWG2907 [expr.const] uninitialized glvalue of type std::nullptr_t appears in the constant expression Jun 18, 2024
@t3nsor
Copy link

t3nsor commented Jun 19, 2024

Needs cv

@t3nsor
Copy link

t3nsor commented Jun 19, 2024

Or maybe not quite. I don't know what we want to do about the volatile std::nullptr_t case.

@jensmaurer
Copy link
Member

Added cv; [conv.lval] has it, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants