Patch for LWG issue #2145
David Blaikie
dblaikie at gmail.com
Wed Aug 21 15:53:21 PDT 2013
On Tue, Aug 20, 2013 at 8:38 PM, Howard Hinnant <hhinnant at apple.com> wrote:
>
> On Aug 20, 2013, at 11:12 PM, David Blaikie <dblaikie at gmail.com> wrote:
>
>> On Tue, Aug 20, 2013 at 11:11 AM, Marshall Clow <mclow.lists at gmail.com> wrote:
>>> http://cplusplus.github.io/LWG/lwg-defects.html#2145
>>>
>>> Mark the constructor for std::error_category as inline and constexpr.
>>> Leave the (existing, out-of-line, non-constexpr) in the dylib for compatibility with existing programs)
>>> No tests, because I don't know how to test it (given that error_category is both an abstract class and has a user-defined destructor)
>>
>> Curious - I haven't dealt with constexpr much, but could you explain
>> further why this is untestable yet is a useful/meaningful change to
>> make?
>
> Sure, fair question.
>
> It is legal to mark a constructor for a class as constexpr, even if that class can never be constructed as a constexpr variable:
>
> struct X
> {
> constexpr X() {}
> ~X(); // disallow constexpr X here
> };
>
> One can legally:
>
> X x;
>
> but not:
>
> constexpr X x;
>
> So why mark X() constexpr?
>
> <disclaimer>I'm learning this in real-time at nearly the same time you are.</disclaimer>
Nice to know I'm not the only one.
> LWG 2145 discusses this a bit: http://cplusplus.github.io/LWG/lwg-defects.html#2145
>
> Apparently if an X is constructed with static scope, if the constructor is marked as constexpr, then it will be constructed at compile time, even if the variable itself is not marked constexpr.
Right - this would be my understanding though differs subtly from
Marshall's claim, which is that this isn't guaranteed. I assume it is
actually guaranteed or it'd be hard to actually write correct code
depending on this feature - it'd be a pure implementation detail
optimization.
> This has been used, for example, in the design of std::mutex:
>
> std::mutex m;
>
> It is important that a global std::mutex be compile-time constructible so as to avoid race conditions during initialization code prior to main(). However you can't make mutexes constexpr:
>
> constexpr std::mutex m; // worthless
>
> because you have to mutate mutexes during program execution (lock them and unlock them).
>
> Testing that X or std::mutex is actually constructed at compile time, and not during initialization prior to main() is challenging. I'm nearly sure it is possible. However I haven't yet succeeded in writing such a test, much less, installing such a test in the libc++ test suite. My current best guess is that such a test would involve at least two translation units, which the current libc++ test suite is not capable of handling.
I don't think it's quite that tricky, but I could be missing something.
Here's a test case that I intended as a runtime test:
#include <cassert>
struct base {
base() {}
virtual ~base() = 0;
};
base::~base() {
}
struct derived: base {
int i;
derived() : i(3) {
}
};
extern derived d;
int func() {
assert(d.i == 3);
return 1;
}
int x = func();
derived d;
int main() {
}
This fails the assertion when derived/base's default ctors are not
constexpr (OK, so a sufficiently advanced compiler could inline the
initialization, I assume? I think global initializers are guaranteed
to occur in the order of declaration in the TU, so I'm not sure it's
actually allowed to do that - I think func() /must/ see 'd.i' as zero
first (or maybe it's UB to access the not-yet-constructed object?))
and passes when they are constexpr.
But in constructing this test case I stumbled across an even easier
way to test, at least with Clang (I'm not sure this is required to
fail to compile, though) as a compile-only test.
Declare derived's ctor constexpr - Clang will produce a compilation
error ("error: constexpr constructor never produces a constant
expression") if the base ctor is not constexpr. This would test the
change that Marshall made.
> As I'm writing this, Marshall has also responded. I agree with what Marshall is saying, and add my own words as well.
>
> If anyone knows of a good way to write a test for the libc++ test suite that would test the presence/absence of a constexpr constructor for a non-literal type, that of course would be a welcome patch. In the meantime, we stumble on. :-)
>
> Howard
>
More information about the cfe-commits
mailing list