On Tue, Aug 20, 2013 at 8:38 PM, Howard Hinnant <[email protected]> wrote: > > On Aug 20, 2013, at 11:12 PM, David Blaikie <[email protected]> wrote: > >> On Tue, Aug 20, 2013 at 11:11 AM, Marshall Clow <[email protected]> >> 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 > _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
