diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-02-27 06:07:25 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-02-27 06:07:25 +0000 |
commit | 79363f5e612c17cd05e1fa888632ee7860ced1ab (patch) | |
tree | 6db72405f1415645715e0aa39ef7637dcd7ecec9 | |
parent | d8e4daca4a44d25a9c09d51def9e3d485d4f302c (diff) |
Ensure that we delete default constructors in the right cases. Don't delete the
default constructor of a union if it has a const member with no user-provided
default constructor.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151516 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 20 | ||||
-rw-r--r-- | test/CXX/special/class.ctor/p5-0x.cpp | 27 |
2 files changed, 25 insertions, 22 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 4f3035466e..73df1c9457 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4485,6 +4485,15 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (inUnion() && !FieldType.isConstQualified()) AllFieldsAreConst = false; + + // 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. + if (!inUnion() && FieldType.isConstQualified() && + !FD->hasInClassInitializer() && + (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) + return true; } else if (CSM == Sema::CXXCopyConstructor) { // For a copy constructor, data members must not be of rvalue reference // type. @@ -4497,13 +4506,6 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { } if (FieldRecord) { - // For a default constructor, a const member must have a user-provided - // default constructor or else be explicitly initialized. - if (CSM == Sema::CXXDefaultConstructor && FieldType.isConstQualified() && - !FD->hasInClassInitializer() && - !FieldRecord->hasUserProvidedDefaultConstructor()) - return true; - // Some additional restrictions exist on the variant members. if (!inUnion() && FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { @@ -4592,10 +4594,6 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { return true; } } - } else if (CSM == Sema::CXXDefaultConstructor && !inUnion() && - FieldType.isConstQualified() && !FD->hasInClassInitializer()) { - // We can't initialize a const member of non-class type to any value. - return true; } else if (IsAssignment && FieldType.isConstQualified()) { // C++11 [class.copy]p23: // -- a non-static data member of const non-class type (or array thereof) diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp index b81755dcd3..6f43446674 100644 --- a/test/CXX/special/class.ctor/p5-0x.cpp +++ b/test/CXX/special/class.ctor/p5-0x.cpp @@ -35,10 +35,16 @@ class Deleted2a { // expected-note {{defined here}} int &a; }; Deleted2a d2a; // expected-error {{implicitly-deleted default constructor}} +struct Deleted2b { // expected-note {{here}} + int &&b; +}; +Deleted2b d2b; // expected-error {{deleted default constructor}} class NotDeleted2a { int &a = n; }; NotDeleted2a nd2a; class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}} NotDeleted2b nd2b; +class NotDeleted2c { int &&a = 0; }; +NotDeleted2c nd2c; // - 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 @@ -59,27 +65,26 @@ class NotDeleted3c { const DefaultedDefCtor2 a = DefaultedDefCtor2(); }; NotDeleted3c nd3c; union NotDeleted3d { const int a; int b; }; NotDeleted3d nd3d; -// FIXME: this class should not have a deleted default constructor. -union NotDeleted3e { const DefaultedDefCtor1 a[42]; int b; }; // unexpected-note {{here}} -NotDeleted3e nd3e; // unexpected-error {{implicitly-deleted default constructor}} -// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2 is -// non-trivial. -union NotDeleted3f { const DefaultedDefCtor2 a; int b; }; // unexpected-note {{here}} -NotDeleted3f nd3f; // unexpected-error {{implicitly-deleted default constructor}} +union NotDeleted3e { const DefaultedDefCtor1 a[42]; int b; }; +NotDeleted3e nd3e; +union NotDeleted3f { const DefaultedDefCtor2 a; int b; }; +NotDeleted3f nd3f; +struct NotDeleted3g { union { const int a; int b; }; }; +NotDeleted3g nd3g; // - X is a union and all of its variant members are of const-qualified type (or // array thereof), union Deleted4a { const int a; const int b; const UserProvidedDefCtor c; }; // expected-note {{here}} Deleted4a d4a; // expected-error {{implicitly-deleted default constructor}} -union Deleted4b { const int a; int b; }; -Deleted4b d4b; +union NotDeleted4a { const int a; int b; }; +NotDeleted4a nd4a; // - X is a non-union class and all members of any anonymous union member are of // const-qualified type (or array thereof), struct Deleted5a { union { const int a; }; union { int b; }; }; // expected-note {{here}} Deleted5a d5a; // expected-error {{implicitly-deleted default constructor}} -struct Deleted5b { union { const int a; int b; }; union { const int c; int d; }; }; -Deleted5b d5b; +struct NotDeleted5a { union { const int a; int b; }; union { const int c; int d; }; }; +NotDeleted5a nd5a; // - any direct or virtual base class, or non-static data member with no // brace-or-equal-initializer, has class type M (or array thereof) and either |