diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-02-14 21:14:13 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-02-14 21:14:13 +0000 |
commit | 1d0c9a8d0573d1f670f484cc17aa94f06be971a5 (patch) | |
tree | e13882eab9af4e402c59d4edad1f43212537293e | |
parent | 75d8ba38965998a07a057c6d1d72359d2cc62c09 (diff) |
PR11650: Implement resolution of core issue 1301. Value initialization can't be
used to construct an object of union type with a deleted default constructor
(plus fixes for some related value-initialization corner cases).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150502 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaInit.cpp | 46 | ||||
-rw-r--r-- | test/CodeGenCXX/pr11676.cpp | 9 | ||||
-rw-r--r-- | test/SemaCXX/dr1301.cpp | 67 |
3 files changed, 107 insertions, 15 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 8376c0d66b..deedff6502 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2699,9 +2699,14 @@ static bool TryListConstructionSpecialCases(Sema &S, QualType DestType, InitializationSequence &Sequence) { // C++11 [dcl.init.list]p3: - // List-initialization of an object of type T is defined as follows: - // - If the initializer list has no elements and T is a class type with - // a default constructor, the object is value-initialized. + // List-initialization of an object or reference of type T is defined as + // follows: + // - If T is an aggregate, aggregate initialization is performed. + if (DestType->isAggregateType()) + return false; + + // - Otherwise, if the initializer list has no elements and T is a class + // type with a default constructor, the object is value-initialized. if (List->getNumInits() == 0) { if (CXXConstructorDecl *DefaultConstructor = S.LookupDefaultConstructor(DestRecordDecl)) { @@ -3549,31 +3554,42 @@ static void TryValueInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitializationSequence &Sequence) { - // C++ [dcl.init]p5: + // C++98 [dcl.init]p5, C++11 [dcl.init]p7: // // To value-initialize an object of type T means: QualType T = Entity.getType(); // -- if T is an array type, then each element is value-initialized; - while (const ArrayType *AT = S.Context.getAsArrayType(T)) - T = AT->getElementType(); + T = S.Context.getBaseElementType(T); if (const RecordType *RT = T->getAs<RecordType>()) { if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // C++98: // -- if T is a class type (clause 9) with a user-declared // constructor (12.1), then the default constructor for T is // called (and the initialization is ill-formed if T has no // accessible default constructor); - // - // FIXME: we really want to refer to a single subobject of the array, - // but Entity doesn't have a way to capture that (yet). - if (ClassDecl->hasUserDeclaredConstructor()) - return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); + if (!S.getLangOptions().CPlusPlus0x) { + if (ClassDecl->hasUserDeclaredConstructor()) + // FIXME: we really want to refer to a single subobject of the array, + // but Entity doesn't have a way to capture that (yet). + return TryConstructorInitialization(S, Entity, Kind, 0, 0, + T, Sequence); + } else { + // C++11: + // -- if T is a class type (clause 9) with either no default constructor + // (12.1 [class.ctor]) or a default constructor that is user-provided + // or deleted, then the object is default-initialized; + CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); + if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) + return TryConstructorInitialization(S, Entity, Kind, 0, 0, + T, Sequence); + } - // -- if T is a (possibly cv-qualified) non-union class type - // without a user-provided constructor, then the object is - // zero-initialized and, if T's implicitly-declared default - // constructor is non-trivial, that constructor is called. + // -- if T is a (possibly cv-qualified) non-union class type without a + // user-provided or deleted default constructor, then the object is + // zero-initialized and, if T has a non-trivial default constructor, + // default-initialized; if ((ClassDecl->getTagKind() == TTK_Class || ClassDecl->getTagKind() == TTK_Struct)) { Sequence.AddZeroInitializationStep(Entity.getType()); diff --git a/test/CodeGenCXX/pr11676.cpp b/test/CodeGenCXX/pr11676.cpp index 78e7a5fe02..896751ad6e 100644 --- a/test/CodeGenCXX/pr11676.cpp +++ b/test/CodeGenCXX/pr11676.cpp @@ -1,8 +1,17 @@ // RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only // CHECK that we don't crash. +// PR11676's example is ill-formed: +/* union _XEvent { }; void ProcessEvent() { _XEvent pluginEvent = _XEvent(); } +*/ + +// Example from PR11665: +void f() { + union U { int field; } u = U(); + (void)U().field; +} diff --git a/test/SemaCXX/dr1301.cpp b/test/SemaCXX/dr1301.cpp new file mode 100644 index 0000000000..e3d63be1f6 --- /dev/null +++ b/test/SemaCXX/dr1301.cpp @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s +struct A { // expected-note 2{{candidate}} + A(int); // expected-note {{candidate}} + int n; +}; +int a = A().n; // expected-error {{no matching constructor}} + +struct B { + B() = delete; // expected-note {{here}} + int n; +}; +int b = B().n; // expected-error {{call to deleted}} + +struct C { // expected-note {{here}} + B b; +}; +int c = C().b.n; // expected-error {{call to deleted}} + +struct D { + D() = default; // expected-note {{here}} + B b; +}; +int d = D().b.n; // expected-error {{call to deleted}} + +struct E { + E() = default; + int n; +}; +int e = E().n; // ok + +struct F { + F(); + int n; +}; +int f = F().n; // ok + +union G { // expected-note {{here}} + F f; +}; +int g = G().f.n; // expected-error {{call to deleted}} + +struct H { + int n; +private: + H(); // expected-note {{here}} +}; +int h = H().n; // expected-error {{private constructor}} + +struct I { // expected-note {{here}} + H h; +}; +int i = I().h.n; // expected-error {{call to deleted}} + +struct J { + J(); + virtual int f(); + int n; +}; +int j1 = J().n; // ok +int j2 = J().f(); // ok + +union K { // expected-note 2{{here}} + J j; + int m; +}; +int k1 = K().j.n; // expected-error {{call to deleted}} +int k2 = K().j.f(); // expected-error {{call to deleted}} |