Unify the codepaths used to verify base and member initializers for explicitly
and implicitly defined constructors. This has a number of benefits: 1. Less code. 2. Explicit and implicit constructors get the same diagnostics. 3. The AST explicitly contains constructor calls from implicit default constructors. This allows handing some cases that previously weren't handled correctly in IRGen without any additional code. Specifically, implicit default constructors containing calls to constructors with default arguments are now handled correctly. llvm-svn: 86500
This commit is contained in:
parent
939ea35244
commit
d7686ef31c
|
@ -430,9 +430,13 @@ def err_implicit_object_parameter_init : Error<
|
|||
"cannot initialize object parameter of type %0 with an expression "
|
||||
"of type %1">;
|
||||
|
||||
def err_missing_default_constructor : Error<
|
||||
"default constructor for %1 is missing in initialization of "
|
||||
"%select{base class|member}0">;
|
||||
def note_field_decl : Note<"member is declared here">;
|
||||
def note_previous_class_decl : Note<
|
||||
"%0 declared here">;
|
||||
def err_missing_default_ctor : Error<
|
||||
"%select{|implicit default }0constructor for %1 must explicitly initialize "
|
||||
"the %select{base class|member}2 %3 which does not have a default "
|
||||
"constructor">;
|
||||
def err_illegal_union_member : Error<
|
||||
"union member %0 has a non-trivial %select{constructor|"
|
||||
"copy constructor|copy assignment operator|destructor}1">;
|
||||
|
@ -763,27 +767,18 @@ def err_param_default_argument_member_template_redecl : Error<
|
|||
"default arguments cannot be added to an out-of-line definition of a member "
|
||||
"of a %select{class template|class template partial specialization|nested "
|
||||
"class in a template}0">;
|
||||
def note_field_decl : Note<"member is declared here">;
|
||||
def err_defining_default_ctor : Error<
|
||||
"cannot define the implicit default constructor for %0, because %select{base class|member's type}1 "
|
||||
"%2 does not have any default constructor">;
|
||||
def note_previous_class_decl : Note<
|
||||
"%0 declared here">;
|
||||
def err_uninitialized_member_for_assign : Error<
|
||||
"cannot define the implicit default assignment operator for %0, because "
|
||||
"non-static %select{reference|const}1 member %2 can't use default "
|
||||
"assignment operator">;
|
||||
def note_first_required_here : Note<
|
||||
"synthesized method is first required here">;
|
||||
def err_unintialized_member : Error<
|
||||
"cannot define the implicit default constructor for %0, because "
|
||||
"%select{reference|const}1 member %2 cannot be default-initialized">;
|
||||
def err_null_intialized_reference_member : Error<
|
||||
"cannot initialize the member to null in default constructor because "
|
||||
"reference member %0 cannot be null-initialized">;
|
||||
def err_unintialized_member_in_ctor : Error<
|
||||
"constructor for %0 must explicitly initialize the "
|
||||
"%select{reference|const}1 member %2 ">;
|
||||
"%select{|implicit default }0constructor for %1 must explicitly initialize "
|
||||
"the %select{reference|const}2 member %3">;
|
||||
|
||||
def err_use_of_default_argument_to_function_declared_later : Error<
|
||||
"use of default argument to function %0 that is declared later in class %1">;
|
||||
|
|
|
@ -1483,64 +1483,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
|
|||
PopCXXTemporary();
|
||||
}
|
||||
|
||||
if (!CD->getNumBaseOrMemberInitializers() && !CD->isTrivial()) {
|
||||
// Nontrivial default constructor with no initializer list. It may still
|
||||
// have bases classes and/or contain non-static data members which require
|
||||
// construction.
|
||||
for (CXXRecordDecl::base_class_const_iterator Base =
|
||||
ClassDecl->bases_begin();
|
||||
Base != ClassDecl->bases_end(); ++Base) {
|
||||
// FIXME. copy assignment of virtual base NYI
|
||||
if (Base->isVirtual())
|
||||
continue;
|
||||
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
if (BaseClassDecl->hasTrivialConstructor())
|
||||
continue;
|
||||
if (CXXConstructorDecl *BaseCX =
|
||||
BaseClassDecl->getDefaultConstructor(getContext())) {
|
||||
LoadOfThis = LoadCXXThis();
|
||||
llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl,
|
||||
BaseClassDecl,
|
||||
/*NullCheckValue=*/false);
|
||||
EmitCXXConstructorCall(BaseCX, Ctor_Complete, V, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
FieldEnd = ClassDecl->field_end();
|
||||
Field != FieldEnd; ++Field) {
|
||||
QualType FieldType = getContext().getCanonicalType((*Field)->getType());
|
||||
const ConstantArrayType *Array =
|
||||
getContext().getAsConstantArrayType(FieldType);
|
||||
if (Array)
|
||||
FieldType = getContext().getBaseElementType(FieldType);
|
||||
if (!FieldType->getAs<RecordType>() || Field->isAnonymousStructOrUnion())
|
||||
continue;
|
||||
const RecordType *ClassRec = FieldType->getAs<RecordType>();
|
||||
CXXRecordDecl *MemberClassDecl =
|
||||
dyn_cast<CXXRecordDecl>(ClassRec->getDecl());
|
||||
if (!MemberClassDecl || MemberClassDecl->hasTrivialConstructor())
|
||||
continue;
|
||||
if (CXXConstructorDecl *MamberCX =
|
||||
MemberClassDecl->getDefaultConstructor(getContext())) {
|
||||
LoadOfThis = LoadCXXThis();
|
||||
LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
|
||||
if (Array) {
|
||||
const llvm::Type *BasePtr = ConvertType(FieldType);
|
||||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr =
|
||||
Builder.CreateBitCast(LHS.getAddress(), BasePtr);
|
||||
EmitCXXAggrConstructorCall(MamberCX, Array, BaseAddrPtr);
|
||||
}
|
||||
else
|
||||
EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(),
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the vtable pointer
|
||||
if (ClassDecl->isDynamicClass()) {
|
||||
if (!LoadOfThis)
|
||||
|
|
|
@ -1747,11 +1747,6 @@ public:
|
|||
const FunctionProtoType *Proto,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RParenLoc);
|
||||
void BuildBaseOrMemberInitializers(ASTContext &C,
|
||||
CXXConstructorDecl *Constructor,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers
|
||||
);
|
||||
|
||||
void DeconstructCallFunction(Expr *FnExpr,
|
||||
NamedDecl *&Function,
|
||||
|
@ -2280,8 +2275,7 @@ public:
|
|||
void SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers,
|
||||
llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
|
||||
llvm::SmallVectorImpl<FieldDecl *>&Members);
|
||||
bool IsImplicitConstructor);
|
||||
|
||||
/// computeBaseOrMembersToDestroy - Compute information in current
|
||||
/// destructor decl's AST of bases and non-static data members which will be
|
||||
|
|
|
@ -1190,8 +1190,7 @@ void
|
|||
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers,
|
||||
llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
|
||||
llvm::SmallVectorImpl<FieldDecl *>&Fields) {
|
||||
bool IsImplicitConstructor) {
|
||||
// We need to build the initializer AST according to order of construction
|
||||
// and not what user specified in the Initializers list.
|
||||
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
|
||||
|
@ -1254,7 +1253,11 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
|||
assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null");
|
||||
CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
|
||||
if (!Ctor) {
|
||||
Bases.push_back(VBase);
|
||||
Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
|
||||
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
|
||||
<< 0 << VBase->getType();
|
||||
Diag(VBaseDecl->getLocation(), diag::note_previous_class_decl)
|
||||
<< Context.getTagDeclType(VBaseDecl);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1299,7 +1302,11 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
|||
assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null");
|
||||
CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context);
|
||||
if (!Ctor) {
|
||||
Bases.push_back(Base);
|
||||
Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
|
||||
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
|
||||
<< 0 << Base->getType();
|
||||
Diag(BaseDecl->getLocation(), diag::note_previous_class_decl)
|
||||
<< Context.getTagDeclType(BaseDecl);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1357,17 +1364,20 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((*Field)->getType()->isDependentType()) {
|
||||
Fields.push_back(*Field);
|
||||
if ((*Field)->getType()->isDependentType())
|
||||
continue;
|
||||
}
|
||||
|
||||
QualType FT = Context.getBaseElementType((*Field)->getType());
|
||||
if (const RecordType* RT = FT->getAs<RecordType>()) {
|
||||
CXXConstructorDecl *Ctor =
|
||||
cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
|
||||
if (!Ctor) {
|
||||
Fields.push_back(*Field);
|
||||
Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
|
||||
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
|
||||
<< 1 << (*Field)->getDeclName();
|
||||
Diag(Field->getLocation(), diag::note_field_decl);
|
||||
Diag(RT->getDecl()->getLocation(), diag::note_previous_class_decl)
|
||||
<< Context.getTagDeclType(RT->getDecl());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1383,22 +1393,24 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
|||
SourceLocation());
|
||||
|
||||
AllToInit.push_back(Member);
|
||||
if (Ctor)
|
||||
MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
|
||||
if (FT.isConstQualified() && (!Ctor || Ctor->isTrivial())) {
|
||||
MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
|
||||
if (FT.isConstQualified() && Ctor->isTrivial()) {
|
||||
Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
|
||||
<< Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
|
||||
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
|
||||
<< 1 << (*Field)->getDeclName();
|
||||
Diag((*Field)->getLocation(), diag::note_declared_at);
|
||||
}
|
||||
}
|
||||
else if (FT->isReferenceType()) {
|
||||
Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
|
||||
<< Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName();
|
||||
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
|
||||
<< 0 << (*Field)->getDeclName();
|
||||
Diag((*Field)->getLocation(), diag::note_declared_at);
|
||||
}
|
||||
else if (FT.isConstQualified()) {
|
||||
Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
|
||||
<< Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
|
||||
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
|
||||
<< 1 << (*Field)->getDeclName();
|
||||
Diag((*Field)->getLocation(), diag::note_declared_at);
|
||||
}
|
||||
}
|
||||
|
@ -1415,29 +1427,6 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Sema::BuildBaseOrMemberInitializers(ASTContext &C,
|
||||
CXXConstructorDecl *Constructor,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers
|
||||
) {
|
||||
llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
|
||||
llvm::SmallVector<FieldDecl *, 4> Members;
|
||||
|
||||
SetBaseOrMemberInitializers(Constructor,
|
||||
Initializers, NumInitializers, Bases, Members);
|
||||
for (unsigned int i = 0; i < Bases.size(); i++) {
|
||||
if (!Bases[i]->getType()->isDependentType())
|
||||
Diag(Bases[i]->getSourceRange().getBegin(),
|
||||
diag::err_missing_default_constructor) << 0 << Bases[i]->getType();
|
||||
}
|
||||
for (unsigned int i = 0; i < Members.size(); i++) {
|
||||
if (!Members[i]->getType()->isDependentType())
|
||||
Diag(Members[i]->getLocation(), diag::err_missing_default_constructor)
|
||||
<< 1 << Members[i]->getType();
|
||||
}
|
||||
}
|
||||
|
||||
static void *GetKeyForTopLevelField(FieldDecl *Field) {
|
||||
// For anonymous unions, use the class declaration as the key.
|
||||
if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
|
||||
|
@ -1462,7 +1451,7 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
|
|||
if (Member->isMemberInitializer()) {
|
||||
FieldDecl *Field = Member->getMember();
|
||||
|
||||
// After BuildBaseOrMemberInitializers call, Field is the anonymous union
|
||||
// After SetBaseOrMemberInitializers call, Field is the anonymous union
|
||||
// data member of the class. Data member used in the initializer list is
|
||||
// in AnonUnionMember field.
|
||||
if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
|
||||
|
@ -1527,9 +1516,9 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
|
|||
return;
|
||||
}
|
||||
|
||||
BuildBaseOrMemberInitializers(Context, Constructor,
|
||||
SetBaseOrMemberInitializers(Constructor,
|
||||
reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
|
||||
NumMemInits);
|
||||
NumMemInits, false);
|
||||
|
||||
if (Constructor->isDependentContext())
|
||||
return;
|
||||
|
@ -1694,9 +1683,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
|
|||
|
||||
if (CXXConstructorDecl *Constructor
|
||||
= dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
|
||||
BuildBaseOrMemberInitializers(Context,
|
||||
Constructor,
|
||||
(CXXBaseOrMemberInitializer **)0, 0);
|
||||
SetBaseOrMemberInitializers(Constructor, 0, 0, false);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -2973,67 +2960,11 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
|||
CXXRecordDecl *ClassDecl
|
||||
= cast<CXXRecordDecl>(Constructor->getDeclContext());
|
||||
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
|
||||
// Before the implicitly-declared default constructor for a class is
|
||||
// implicitly defined, all the implicitly-declared default constructors
|
||||
// for its base class and its non-static data members shall have been
|
||||
// implicitly defined.
|
||||
bool err = false;
|
||||
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
|
||||
E = ClassDecl->bases_end(); Base != E; ++Base) {
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
if (!BaseClassDecl->hasTrivialConstructor()) {
|
||||
if (CXXConstructorDecl *BaseCtor =
|
||||
BaseClassDecl->getDefaultConstructor(Context))
|
||||
MarkDeclarationReferenced(CurrentLocation, BaseCtor);
|
||||
else {
|
||||
Diag(CurrentLocation, diag::err_defining_default_ctor)
|
||||
<< Context.getTagDeclType(ClassDecl) << 0
|
||||
<< Context.getTagDeclType(BaseClassDecl);
|
||||
Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl)
|
||||
<< Context.getTagDeclType(BaseClassDecl);
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
E = ClassDecl->field_end(); Field != E; ++Field) {
|
||||
QualType FieldType = Context.getCanonicalType((*Field)->getType());
|
||||
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
|
||||
FieldType = Array->getElementType();
|
||||
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
|
||||
CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||
if (!FieldClassDecl->hasTrivialConstructor()) {
|
||||
if (CXXConstructorDecl *FieldCtor =
|
||||
FieldClassDecl->getDefaultConstructor(Context))
|
||||
MarkDeclarationReferenced(CurrentLocation, FieldCtor);
|
||||
else {
|
||||
Diag(CurrentLocation, diag::err_defining_default_ctor)
|
||||
<< Context.getTagDeclType(ClassDecl) << 1 <<
|
||||
Context.getTagDeclType(FieldClassDecl);
|
||||
Diag((*Field)->getLocation(), diag::note_field_decl);
|
||||
Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl)
|
||||
<< Context.getTagDeclType(FieldClassDecl);
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
} else if (FieldType->isReferenceType()) {
|
||||
Diag(CurrentLocation, diag::err_unintialized_member)
|
||||
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
|
||||
Diag((*Field)->getLocation(), diag::note_declared_at);
|
||||
err = true;
|
||||
} else if (FieldType.isConstQualified()) {
|
||||
Diag(CurrentLocation, diag::err_unintialized_member)
|
||||
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
|
||||
Diag((*Field)->getLocation(), diag::note_declared_at);
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
Constructor->setUsed();
|
||||
else
|
||||
Constructor->setInvalidDecl();
|
||||
|
||||
SetBaseOrMemberInitializers(Constructor, 0, 0, true);
|
||||
|
||||
Constructor->setUsed();
|
||||
return;
|
||||
}
|
||||
|
||||
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
|
||||
|
|
|
@ -12,7 +12,7 @@ struct X { // expected-note{{here}}
|
|||
|
||||
void g() { }
|
||||
|
||||
struct Inner {
|
||||
struct Inner { // expected-error{{implicit default}}
|
||||
T value; // expected-note {{member is declared here}}
|
||||
};
|
||||
|
||||
|
@ -26,8 +26,7 @@ IntHolder &test_X_IntHolderInt(X<IntHolder, int> xih) {
|
|||
xih.g(); // okay
|
||||
xih.f(); // expected-note{{instantiation}}
|
||||
|
||||
// FIXME: diagnostic here has incorrect reason (PR5154)
|
||||
X<IntHolder, int>::Inner inner; // expected-error{{implicit default}}
|
||||
X<IntHolder, int>::Inner inner;
|
||||
|
||||
return X<IntHolder, int>::value; // expected-note{{instantiation}}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t-64.ll
|
||||
// RUN: FileCheck -check-prefix LPLL64 --input-file=%t-64.ll %s
|
||||
|
||||
// XFAIL: *
|
||||
|
||||
struct B {
|
||||
virtual void bar1();
|
||||
|
|
|
@ -99,7 +99,9 @@ struct Current : Derived {
|
|||
|
||||
// FIXME. This is bad message!
|
||||
struct M { // expected-note {{candidate function}} \
|
||||
// expected-note {{candidate function}}
|
||||
// expected-note {{candidate function}} \
|
||||
// expected-note {{declared here}} \
|
||||
// expected-note {{declared here}}
|
||||
M(int i, int j); // expected-note {{candidate function}} \
|
||||
// // expected-note {{candidate function}}
|
||||
};
|
||||
|
@ -110,9 +112,10 @@ struct N : M {
|
|||
M m1;
|
||||
};
|
||||
|
||||
struct P : M { // expected-error {{default constructor for 'struct M' is missing in initialization of base class}}
|
||||
P() { }
|
||||
M m; // expected-error {{default constructor for 'struct M' is missing in initialization of member}}
|
||||
struct P : M {
|
||||
P() { } // expected-error {{base class 'struct M'}} \
|
||||
// expected-error {{member 'm'}}
|
||||
M m; // expected-note {{member is declared here}}
|
||||
};
|
||||
|
||||
struct Q {
|
||||
|
|
|
@ -9,18 +9,18 @@ struct X2 : X1 { // expected-note {{'struct X2' declared here}} \
|
|||
X2(int);
|
||||
};
|
||||
|
||||
struct X3 : public X2 {
|
||||
struct X3 : public X2 { // expected-error {{must explicitly initialize the base class 'struct X2'}}
|
||||
};
|
||||
X3 x3; // expected-error {{cannot define the implicit default constructor for 'struct X3', because base class 'struct X2' does not have any default constructor}}
|
||||
X3 x3;
|
||||
|
||||
|
||||
struct X4 {
|
||||
struct X4 { // expected-error {{must explicitly initialize the member 'x2'}} \
|
||||
// expected-error {{must explicitly initialize the reference member 'rx2'}}
|
||||
X2 x2; // expected-note {{member is declared here}}
|
||||
X2 & rx2; // expected-note {{declared at}}
|
||||
};
|
||||
|
||||
X4 x4; // expected-error {{cannot define the implicit default constructor for 'struct X4', because member's type 'struct X2' does not have any default constructor}} \
|
||||
// expected-error {{cannot define the implicit default constructor for 'struct X4', because reference member 'rx2' cannot be default-initialized}}
|
||||
X4 x4;
|
||||
|
||||
|
||||
struct Y1 { // has no implicit default constructor
|
||||
|
@ -45,12 +45,12 @@ Y4 y4;
|
|||
// More tests
|
||||
|
||||
|
||||
struct Z1 {
|
||||
struct Z1 { // expected-error {{must explicitly initialize the reference member 'z'}} \
|
||||
// expected-error {{must explicitly initialize the const member 'c1'}}
|
||||
int& z; // expected-note {{declared at}}
|
||||
const int c1; // expected-note {{declared at}}
|
||||
volatile int v1;
|
||||
};
|
||||
|
||||
Z1 z1; // expected-error {{cannot define the implicit default constructor for 'struct Z1', because reference member 'z' cannot be default-initialized}} \
|
||||
// expected-error {{cannot define the implicit default constructor for 'struct Z1', because const member 'c1' cannot be default-initialized}}
|
||||
Z1 z1;
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
|
||||
|
||||
struct A {
|
||||
struct A { // expected-error {{implicit default constructor for 'struct A' must explicitly initialize the const member 'i'}}
|
||||
const int i; // expected-note {{declared at}}
|
||||
virtual void f() { }
|
||||
};
|
||||
|
||||
int main () {
|
||||
(void)A(); // expected-error {{cannot define the implicit default constructor for 'struct A', because const member 'i' cannot be default-initialized}}
|
||||
(void)A();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue