Patch for LWG issue #2145
Howard Hinnant
hhinnant at apple.com
Thu Aug 22 10:44:55 PDT 2013
Thanks David. This is a good suggestion. Committed revision 189034.
Howard
On Aug 21, 2013, at 6:53 PM, David Blaikie <dblaikie at gmail.com> wrote:
> 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