[cfe-commits] [PATCH] Implement C++11 in-class member initializers

Richard Smith richard at metafoo.co.uk
Mon May 23 17:56:33 PDT 2011


Hi all,

Same again but with three forgotten tests svn added. Moral: don't send
email at 2am!

Regards,
Richard

On Tue, May 24, 2011 01:48, Richard Smith wrote:
> Hi all,
>
>
> The attached patch adds support for C++11's in-class initialization of
> non-static data members:
>
> struct S { int n = 0; };
>
>
> For the most part, this is straightforward: the initializer is stored in
> the FieldDecl, parsing is delayed until the outermost class is complete (as
> is effectively required by the standard), and CXXConstructorInit has been
> extended to optionally pick the initializer from the FieldDecl (this
> allows the constructor definition to be built before the initializer is
> parsed).
>
> There is a hotch-potch of horrifying holes here, however:
>
>
> 1) C++11 doesn't allow in-class initialization of bit-fields. This would
> be a useful extension, and I think it's simply an oversight in the
> standard. I'm currently packing the initializer and bitfield width into
> the same pointer, so some rework is required to support this.
>
> 2) There's an ordering issue with the implicit exception specification
> for a defaulted default constructor and in-class initializers. Consider:
>
> template<bool b> struct T { typedef int f; }; template<> struct T<true> {
> static void f(); }; struct S { bool b = T<noexcept(S())>::f(); };
>
>
> This is well-formed, but is meaningless: if S::S() is noexcept, then it
> is not, and vice versa. With a little tweaking, we can make it impossible
> to parse such things at all. I have implemented an ad-hoc rule to allow
> clang to try to escape from this pit with some dignity: while performing
> the deferred parsing of in-class initializers, the exception specification
> of the constructor (if needed) is temporarily set to a new value,
> EST_Unknown, and any expression which depends on whether it is noexcept
> is considered ill-formed and diagnosed.
>
> Eventually, the same rule will need to be used while performing deferred
> parsing for default arguments and exception specifications, which suffer
> from the same problem: see test/SemaCXX/implicit-exception-spec.cpp.
> Implicit constexpr on defaulted default constructors will also suffer a
> similar problem, as will exception specifications for inherited
> constructors (if the standard is fixed to compute them correctly).
>
> 3) Similarly to issue (2), we have a problem with the
> __has_nothrow_constructor type trait within the definition of a class with
>  an in-class initializer. The specification for this trait says that it
> shall be true only if the constructor is known to be non-throwing, which
> isn't the case until we have parsed all the in-class initializers.
> Therefore it currently produces 'false' in such cases (and the value can
> subsequently be 'true' once the class is fully parsed). I'm not
> particularly happy with this, and would prefer for us to diagnose such
> uses.
>
> 4) The implicit exception specifications of defaulted default
> constructors for classes containing in-class initializers, as implemented
> in this patch, do not conform to the standard. The standard says that an
> implicit exception specification throws an exception E iff any function it
> directly invokes does. This is wrong in two ways:
>
> void f(); struct S { int n = (throw "eep", 0); }; struct T { bool b =
> nothrow(f()); };
>
> In the first example, S::S() should be implicitly declared as noexcept,
> because it does not invoke any throwing functions (despite containing a
> throw-expression!). In the second example, S::S() should be implicitly
> declared as noexcept(false), since the standard does not require a
> function to be potentially-evaluated for it to be invoked ("invoked"
> isn't formally defined, so this point is debatable, but that itself is a
> defect).
>
> I think clang should aim to implement the intent of the standard here:
> the exception specification should include an exception E iff the implicit
>  body could throw E. This is partially implemented: the default
> constructor is set to nothrow(false) if the in-class initializer can
> throw. A full solution would require extending the Expr::CanThrow
> mechanism to provide a list of potentially-thrown exceptions, but that is
> beyond the scope of this patch (especially considering that it does not
> match the standard).
>
> Another corner case we currently get wrong here is that the implicit
> default constructor can invoke functions in a default argument for a base
> or member default constructor, and such functions' exception
> specifications are not currently being considered. This patch does
> nothing to address that. That's PR9918.
>
> 5) This patch incorporates an interpretation of the proposed resolution
> to C++ core issue 325. Specifically, we reject this:
>
>
> struct S { int n = T<0, 0>::f(); template<int, int> struct T { static int
> f(); }; };
>
>
> because the ',' is interpreted as the end of the initializer.
>
>
>
> A couple of other notes on the implementation:
>
>
> * There's an outstanding issue with initializers being provided for
> typedefs in a class: currently clang asserts. This will be addressed by a
> later patch. * There's a pre-existing issue with clang accepting
> initializers for multiple members of a union: PR9996. This issue affects
> in-class initializers too. * This patch also addresses in-class
> initialization of static members of auto type. * We were parsing
> __attributes__/__asm__ and initializers in a
> non-gcc-compatible order; I've swapped them over.
>
> Apologies for the length of this email; I lack the time to make it
> shorter.
>
> I'd welcome any and all comments!
> Thanks, Richard
-------------- next part --------------
A non-text attachment was scrubbed...
Name: clang-in-class-member-init.diff
Type: text/x-patch
Size: 118346 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20110524/320d5964/attachment.bin>


More information about the cfe-commits mailing list