Thanks David. This is a good suggestion. Committed revision 189034. Howard
On Aug 21, 2013, at 6:53 PM, David Blaikie <[email protected]> wrote: > 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
