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

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

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.

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

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; // undefined behavior: uninitialized read of \tcode{s.a}

};
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)

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

Successfully merging this pull request may close these issues.

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