diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -155,6 +155,9 @@ a coroutine will no longer generate a call to a global allocation function with the signature (std::size_t, p0, ..., pn). This fixes Issue `Issue 54881 `_. +- Implement `CWG 2394 `_: Const class members + may be initialized with a defaulted default constructor under the same + conditions it would be allowed for a const object elsewhere. Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9213,13 +9213,12 @@ << !!ICI << MD->getParent() << FD << FieldType << /*Reference*/0; return true; } - // C++11 [class.ctor]p5: any non-variant non-static data member of - // const-qualified type (or array thereof) with no - // brace-or-equal-initializer does not have a user-provided default - // constructor. + // C++11 [class.ctor]p5 (modified by DR2394): any non-variant non-static + // data member of const-qualified type (or array thereof) with no + // brace-or-equal-initializer is not const-default-constructible. if (!inUnion() && FieldType.isConstQualified() && !FD->hasInClassInitializer() && - (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) { + (!FieldRecord || !FieldRecord->allowConstDefaultInit())) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) << !!ICI << MD->getParent() << FD << FD->getType() << /*Const*/1; diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp --- a/clang/test/CXX/drs/dr23xx.cpp +++ b/clang/test/CXX/drs/dr23xx.cpp @@ -158,3 +158,14 @@ } } //namespace dr2303 #endif + +namespace dr2394 { // dr2394: 15 + +struct A {}; +const A a; + +// Now allowed to default-init B. +struct B { const A a; }; +B b; + +} diff --git a/clang/test/CXX/special/class.ctor/p5-0x.cpp b/clang/test/CXX/special/class.ctor/p5-0x.cpp --- a/clang/test/CXX/special/class.ctor/p5-0x.cpp +++ b/clang/test/CXX/special/class.ctor/p5-0x.cpp @@ -2,6 +2,8 @@ struct DefaultedDefCtor1 {}; struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; }; +struct DefaultedDefCtorUninitialized1 { int x; }; +struct DefaultedDefCtorUninitialized2 { int x; DefaultedDefCtorUninitialized2() = default; }; struct DeletedDefCtor { DeletedDefCtor() = delete; DeletedDefCtor(int); }; // expected-note {{explicitly marked deleted here}} class PrivateDefCtor { PrivateDefCtor() = default; public: PrivateDefCtor(int); }; struct DeletedDtor { ~DeletedDtor() = delete; }; // expected-note 4{{explicitly marked deleted here}} @@ -51,21 +53,20 @@ NotDeleted2d nd2d; // expected-note {{first required here}} // - any non-variant non-static data member of const qualified type (or array -// thereof) with no brace-or-equal-initializer does not have a user-provided -// default constructor, +// thereof) with no brace-or-equal-initializer is not const-default-constructible class Deleted3a { const int a; }; // expected-note {{because field 'a' of const-qualified type 'const int' would not be initialized}} \ expected-warning {{does not declare any constructor}} \ expected-note {{will never be initialized}} Deleted3a d3a; // expected-error {{implicitly-deleted default constructor}} -class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{because field 'a' of const-qualified type 'const DefaultedDefCtor1[42]' would not be initialized}} +class Deleted3b { const DefaultedDefCtorUninitialized1 a[42]; }; // expected-note {{because field 'a' of const-qualified type 'const DefaultedDefCtorUninitialized1[42]' would not be initialized}} Deleted3b d3b; // expected-error {{implicitly-deleted default constructor}} -class Deleted3c { const DefaultedDefCtor2 a; }; // expected-note {{because field 'a' of const-qualified type 'const DefaultedDefCtor2' would not be initialized}} +class Deleted3c { const DefaultedDefCtorUninitialized2 a; }; // expected-note {{because field 'a' of const-qualified type 'const DefaultedDefCtorUninitialized2' would not be initialized}} Deleted3c d3c; // expected-error {{implicitly-deleted default constructor}} class NotDeleted3a { const int a = 0; }; NotDeleted3a nd3a; -class NotDeleted3b { const DefaultedDefCtor1 a[42] = {}; }; +class NotDeleted3b { const DefaultedDefCtorUninitialized1 a[42] = {}; }; NotDeleted3b nd3b; -class NotDeleted3c { const DefaultedDefCtor2 a = DefaultedDefCtor2(); }; +class NotDeleted3c { const DefaultedDefCtorUninitialized2 a = DefaultedDefCtorUninitialized2(); }; NotDeleted3c nd3c; union NotDeleted3d { const int a; int b; }; NotDeleted3d nd3d; @@ -75,6 +76,10 @@ NotDeleted3f nd3f; struct NotDeleted3g { union { const int a; int b; }; }; NotDeleted3g nd3g; +struct NotDeleted3h { const DefaultedDefCtor1 a[42]; }; +NotDeleted3h nd3h; +struct NotDeleted3i { const DefaultedDefCtor2 a; }; +NotDeleted3i nd3i; // - X is a union and all of its variant members are of const-qualified type (or // array thereof), diff --git a/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp b/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp --- a/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp +++ b/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp @@ -48,8 +48,12 @@ }; good g; +struct bad_const_inner { + int x; +}; + struct bad_const { - const good g; // expected-note {{field 'g' of const-qualified type 'const good' would not be initialized}} + const bad_const_inner g; // expected-note {{field 'g' of const-qualified type 'const bad_const_inner' would not be initialized}} }; bad_const bc; // expected-error {{call to implicitly-deleted default constructor}} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -14178,7 +14178,7 @@ 2394 CD5 Const-default-constructible for members - Unknown + Clang 15 2395