Skip to content

[dcl.constexpr] Modernize example of constexpr-usable functions #6484

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Eisenwave
Copy link
Contributor

@Eisenwave Eisenwave commented Aug 20, 2023

Fixes #5718.

image

As explained in the issue, the example has become largely noise because of how many restrictions have been lifted in constexpr functions. The intuition of most users is probably that abs, long_max, prev and others should be constexpr, unless proven otherwise. This shift in mentality calls for examples which demonstrate what isn't constexpr-usable, rather than what is.

@Eisenwave Eisenwave force-pushed the modernize-constexpr-example branch from 718450a to 3d9d38a Compare August 20, 2023 21:14
@Eisenwave Eisenwave force-pushed the modernize-constexpr-example branch from 3d9d38a to 1145c0e Compare August 20, 2023 21:18
constexpr int uninit() {
struct { int a; } s;
return s.a; // error: uninitialized read of \tcode{s.a}
constexpr int stinit(int n) { // \tcode{stinit} is constexpr-usable, but \tcode{stinit}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The paragraph the example is attached to defines constexpr-suitable, so I think that's what you meant.

Suggested change
constexpr int stinit(int n) { // \tcode{stinit} is constexpr-usable, but \tcode{stinit}
constexpr int stinit(int n) { // \tcode{stinit} is constexpr-suitable, but \tcode{stinit}

int r = 1;
while (--n > 0) r *= x;
return r;
constexpr int uninit() { // \tcode{uninit} is constexpr-usable, but a program which calls
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
constexpr int uninit() { // \tcode{uninit} is constexpr-usable, but a program which calls
constexpr int uninit() { // \tcode{uninit} is constexpr-suitable, but a program which calls

}
return n;
constexpr std::generator<int> iota(int n = 0) {
while (true) co_yield n++; // error: \tcode{co_yield} cannot be used in a constexpr function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this example can be improved.
[expr.const] bans co_await and co_yield,
but [dcl.constexpr]p3 (the paragraph the example is attached to)
bans a constexpr function that is a coroutine.
So I think it might better to use co_return instead,
which isn't banned by [expr.const].

Copy link
Member

@jensmaurer jensmaurer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about constexpr, not about [expr.const].
The focus should be on stuff that is ok/ill-formed because of [dcl.constexpr].
Having one (punchy) example of something that is ok by [dcl.constexpr] but ill-formed if invoked in a constant-expression context in all cases is fine. An unconditional throw-expression is good enough for that.

Copy link
Contributor

@frederick-vs-ja frederick-vs-ja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "OK" in this example means constexpr-usable/constexpr-suitable. So perhaps we should only use the simple "OK".

Comment on lines +892 to +894
constexpr int uninit() { // \tcode{uninit} is constexpr-usable, but a program which calls
struct { int a; } s; // \tcode{uninit} in a constant expression is ill-formed
return s.a;
Copy link
Contributor

@frederick-vs-ja frederick-vs-ja Oct 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
constexpr int uninit() { // \tcode{uninit} is constexpr-usable, but a program which calls
struct { int a; } s; // \tcode{uninit} in a constant expression is ill-formed
return s.a;
constexpr int uninit() { // OK, but never produces a core constant expression
struct { int a; } s;
return s.a; // erroneous behavior: uninitialized read of \tcode{s.a}

Edit: In C++26, the UB is changed to EB.

};
struct Derived : virtual Base {
constexpr Derived() = default; // error: constructor cannot be constexpr in a
}; // class or struct with virtual base classes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"class or struct" -> "class"

("class" covers all of union, class, struct)

@jensmaurer jensmaurer added the changes requested Changes to the wording or approach have been requested and not yet applied. label Aug 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changes requested Changes to the wording or approach have been requested and not yet applied.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Example "uninit" in [dcl.constexpr] no longer valid
4 participants