Open Rush10233 opened 3 months ago
For the first one (normal member function)
In C++20 (and before), this matches all of the requirements https://timsong-cpp.github.io/cppwp/n4861/dcl.constexpr#3
Notably C++20 had a requirement for constructors/destructors only:
- if the function is a constructor or destructor, its class shall not have any virtual base classes;
Which is being applied to all member functions by Clang. Stuff like this needs to be accepted: https://godbolt.org/z/76WzG3jv6
For the second one (defaulted copy-assign operator): In C++23 after p2448r2, it should be accepted.
The constructors not being allowed to be constexpr
is still not allowed in C++23. https://eel.is/c++draft/dcl.constexpr#3.2
A function is constexpr-suitable if:
- [...]
- if the function is a constructor or destructor, its class does not have any virtual base classes. Except for instantiated constexpr functions, non-templated constexpr functions shall be constexpr-suitable.
So constexpr derived(const derived &)=default;
is always ill-formed.
I believe gcc shouldn't accept it before C++23. https://timsong-cpp.github.io/cppwp/n4861/dcl.fct.def.default#3.sentence-1 (C++20)
An explicitly-defaulted function that is not defined as deleted may be declared
constexpr
orconsteval
only if it is constexpr-compatible ([special]).
There is even a FIXME comment about this: https://github.com/llvm/llvm-project/blob/208a08c3b7b00c05629c3f18811aac81f17cd81b/clang/lib/Sema/SemaDeclCXX.cpp#L1820-L1841
@llvm/issue-subscribers-clang-frontend
Author: None (Rush10233)
In C++20 (and before), this matches all of the requirements https://timsong-cpp.github.io/cppwp/n4861/dcl.constexpr#3
However, in this example it seems that tst
can never produce a constant (sub)expression (even in C++23).
As derived
is not an implicit-lifetime type and can't have any constexpr
constructor due to the virtual base, it is impossible to start lifetime of a derived
object in constant evaluation. As a result, a call to the non-static member function tst
is not allowed in constant evaluation as any attempt would cause UB, and it's ill-formed, no diagnostic required to mark tst
constexpr
until C++23.
In C++23, it should be well-formed to make tst
constexpr
.
@frederick-vs-ja You don't need an object to start its lifetime inside the constant expression to call a member function on it (https://stackoverflow.com/q/32803708)
struct base { };
struct derived : virtual base {
constexpr int tst() {return 1;}
};
extern derived d;
static_assert(d.tst() == 1); // Well formed in C++20 (C++11 even I think)
@frederick-vs-ja You don't need an object to start its lifetime inside the constant expression to call a member function on it (https://stackoverflow.com/q/32803708)
struct base { }; struct derived : virtual base { constexpr int tst() {return 1;} }; extern derived d; static_assert(d.tst() == 1); // Well formed in C++20 (C++11 even I think)
Yeah, you're right (thanks to P2280R4). Not sure whether #95474 should also address this.
It was valid even before because there are no unknown references (d
is a constant glvalue, and there is nothing with reference or pointer type), so this is unrelated. See the second example (auto rando(
) here: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2280r4.html#other-examples which is only invalid because of the reference type, and would be valid if the parameter was by-value.
Wow. Looks like I got this wrong 13 years ago. Oops!
First, the following code is rejected by clang but accepted by other compilers like GCC, MSVC, and ICC:
https://godbolt.org/z/rj63nKP4v
Clang reports the following message:
The diagnostic seems not such necessary because member function
tst
doesn't involve any override and can be specified during compile stage.It's more interesting that the overloaded copy assignment operator is also accepted by other compilers, which definitely contains the instantiation of the virtual base class:
https://godbolt.org/z/rYPEYTex8
Copy ctors and move ctors are always rejected though.