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).

llvm-svn: 150502
This commit is contained in:
Richard Smith 2012-02-14 21:14:13 +00:00
parent b2cde923cf
commit 1bfe068e71
3 changed files with 107 additions and 15 deletions

View File

@ -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());

View File

@ -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;
}

View File

@ -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}}