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