зеркало из https://github.com/microsoft/clang-1.git
Issue diagnostics in variety of situations involving
reference/const data members when user has declared the constructor. This necessitated some non-minor refactoring. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80934 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
b8b844b925
Коммит
80545ad0f9
|
@ -1039,12 +1039,13 @@ public:
|
|||
return NumBaseOrMemberInitializers;
|
||||
}
|
||||
|
||||
void setBaseOrMemberInitializers(ASTContext &C,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers,
|
||||
llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
|
||||
llvm::SmallVectorImpl<FieldDecl *>&Members);
|
||||
void setNumBaseOrMemberInitializers(unsigned numBaseOrMemberInitializers) {
|
||||
NumBaseOrMemberInitializers = numBaseOrMemberInitializers;
|
||||
}
|
||||
|
||||
void setBaseOrMemberInitializers(CXXBaseOrMemberInitializer ** initializers) {
|
||||
BaseOrMemberInitializers = initializers;
|
||||
}
|
||||
/// isDefaultConstructor - Whether this constructor is a default
|
||||
/// constructor (C++ [class.ctor]p5), which can be used to
|
||||
/// default-initialize a class of this type.
|
||||
|
|
|
@ -714,6 +714,12 @@ def note_first_required_here : Note<
|
|||
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 ">;
|
||||
|
||||
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">;
|
||||
|
|
|
@ -583,159 +583,6 @@ CXXDestructorDecl::computeBaseOrMembersToDestroy(ASTContext &C) {
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXXConstructorDecl::setBaseOrMemberInitializers(
|
||||
ASTContext &C,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers,
|
||||
llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
|
||||
llvm::SmallVectorImpl<FieldDecl *>&Fields) {
|
||||
// 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>(getDeclContext());
|
||||
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
|
||||
llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
|
||||
bool HasDependentBaseInit = false;
|
||||
|
||||
for (unsigned i = 0; i < NumInitializers; i++) {
|
||||
CXXBaseOrMemberInitializer *Member = Initializers[i];
|
||||
if (Member->isBaseInitializer()) {
|
||||
if (Member->getBaseClass()->isDependentType())
|
||||
HasDependentBaseInit = true;
|
||||
AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
|
||||
} else {
|
||||
AllBaseFields[Member->getMember()] = Member;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasDependentBaseInit) {
|
||||
// FIXME. This does not preserve the ordering of the initializers.
|
||||
// Try (with -Wreorder)
|
||||
// template<class X> struct A {};
|
||||
// template<class X> struct B : A<X> {
|
||||
// B() : x1(10), A<X>() {}
|
||||
// int x1;
|
||||
// };
|
||||
// B<int> x;
|
||||
// On seeing one dependent type, we should essentially exit this routine
|
||||
// while preserving user-declared initializer list. When this routine is
|
||||
// called during instantiatiation process, this routine will rebuild the
|
||||
// oderdered initializer list correctly.
|
||||
|
||||
// If we have a dependent base initialization, we can't determine the
|
||||
// association between initializers and bases; just dump the known
|
||||
// initializers into the list, and don't try to deal with other bases.
|
||||
for (unsigned i = 0; i < NumInitializers; i++) {
|
||||
CXXBaseOrMemberInitializer *Member = Initializers[i];
|
||||
if (Member->isBaseInitializer())
|
||||
AllToInit.push_back(Member);
|
||||
}
|
||||
} else {
|
||||
// Push virtual bases before others.
|
||||
for (CXXRecordDecl::base_class_iterator VBase =
|
||||
ClassDecl->vbases_begin(),
|
||||
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
|
||||
if (VBase->getType()->isDependentType())
|
||||
continue;
|
||||
if (CXXBaseOrMemberInitializer *Value =
|
||||
AllBaseFields.lookup(VBase->getType()->getAs<RecordType>()))
|
||||
AllToInit.push_back(Value);
|
||||
else {
|
||||
CXXRecordDecl *VBaseDecl =
|
||||
cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
|
||||
assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null");
|
||||
if (!VBaseDecl->getDefaultConstructor(C))
|
||||
Bases.push_back(VBase);
|
||||
CXXBaseOrMemberInitializer *Member =
|
||||
new (C) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0,
|
||||
VBaseDecl->getDefaultConstructor(C),
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
AllToInit.push_back(Member);
|
||||
}
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::base_class_iterator Base =
|
||||
ClassDecl->bases_begin(),
|
||||
E = ClassDecl->bases_end(); Base != E; ++Base) {
|
||||
// Virtuals are in the virtual base list and already constructed.
|
||||
if (Base->isVirtual())
|
||||
continue;
|
||||
// Skip dependent types.
|
||||
if (Base->getType()->isDependentType())
|
||||
continue;
|
||||
if (CXXBaseOrMemberInitializer *Value =
|
||||
AllBaseFields.lookup(Base->getType()->getAs<RecordType>()))
|
||||
AllToInit.push_back(Value);
|
||||
else {
|
||||
CXXRecordDecl *BaseDecl =
|
||||
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
|
||||
if (!BaseDecl->getDefaultConstructor(C))
|
||||
Bases.push_back(Base);
|
||||
CXXBaseOrMemberInitializer *Member =
|
||||
new (C) CXXBaseOrMemberInitializer(Base->getType(), 0, 0,
|
||||
BaseDecl->getDefaultConstructor(C),
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
AllToInit.push_back(Member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// non-static data members.
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
E = ClassDecl->field_end(); Field != E; ++Field) {
|
||||
if ((*Field)->isAnonymousStructOrUnion()) {
|
||||
if (const RecordType *FieldClassType =
|
||||
Field->getType()->getAs<RecordType>()) {
|
||||
CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||
for(RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
|
||||
EA = FieldClassDecl->field_end(); FA != EA; FA++) {
|
||||
if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) {
|
||||
// 'Member' is the anonymous union field and 'AnonUnionMember' is
|
||||
// set to the anonymous union data member used in the initializer
|
||||
// list.
|
||||
Value->setMember(*Field);
|
||||
Value->setAnonUnionMember(*FA);
|
||||
AllToInit.push_back(Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
|
||||
AllToInit.push_back(Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
QualType FT = C.getBaseElementType((*Field)->getType());
|
||||
if (const RecordType* RT = FT->getAs<RecordType>()) {
|
||||
CXXConstructorDecl *Ctor =
|
||||
cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(C);
|
||||
if (!Ctor && !FT->isDependentType())
|
||||
Fields.push_back(*Field);
|
||||
CXXBaseOrMemberInitializer *Member =
|
||||
new (C) CXXBaseOrMemberInitializer((*Field), 0, 0,
|
||||
Ctor,
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
AllToInit.push_back(Member);
|
||||
}
|
||||
}
|
||||
|
||||
NumInitializers = AllToInit.size();
|
||||
if (NumInitializers > 0) {
|
||||
NumBaseOrMemberInitializers = NumInitializers;
|
||||
BaseOrMemberInitializers =
|
||||
new (C) CXXBaseOrMemberInitializer*[NumInitializers];
|
||||
for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
|
||||
BaseOrMemberInitializers[Idx] = AllToInit[Idx];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXXConstructorDecl::Destroy(ASTContext& C) {
|
||||
C.Deallocate(BaseOrMemberInitializers);
|
||||
|
|
|
@ -2175,7 +2175,13 @@ public:
|
|||
unsigned NumArgs, SourceLocation IdLoc,
|
||||
SourceLocation RParenLoc,
|
||||
CXXRecordDecl *ClassDecl);
|
||||
|
||||
|
||||
void setBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers,
|
||||
llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
|
||||
llvm::SmallVectorImpl<FieldDecl *>&Members);
|
||||
|
||||
void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
|
||||
|
||||
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
|
||||
|
|
|
@ -792,6 +792,11 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
|
|||
} else if (!HasDependentArg) {
|
||||
Expr *NewExp;
|
||||
if (NumArgs == 0) {
|
||||
if (FieldType->isReferenceType()) {
|
||||
Diag(IdLoc, diag::err_null_intialized_reference_member)
|
||||
<< Member->getDeclName();
|
||||
return Diag(Member->getLocation(), diag::note_declared_at);
|
||||
}
|
||||
NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc);
|
||||
NumArgs = 1;
|
||||
}
|
||||
|
@ -889,6 +894,175 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
|
|||
NumArgs, C, IdLoc, RParenLoc);
|
||||
}
|
||||
|
||||
void
|
||||
Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers,
|
||||
llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
|
||||
llvm::SmallVectorImpl<FieldDecl *>&Fields) {
|
||||
// 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());
|
||||
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
|
||||
llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
|
||||
bool HasDependentBaseInit = false;
|
||||
|
||||
for (unsigned i = 0; i < NumInitializers; i++) {
|
||||
CXXBaseOrMemberInitializer *Member = Initializers[i];
|
||||
if (Member->isBaseInitializer()) {
|
||||
if (Member->getBaseClass()->isDependentType())
|
||||
HasDependentBaseInit = true;
|
||||
AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
|
||||
} else {
|
||||
AllBaseFields[Member->getMember()] = Member;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasDependentBaseInit) {
|
||||
// FIXME. This does not preserve the ordering of the initializers.
|
||||
// Try (with -Wreorder)
|
||||
// template<class X> struct A {};
|
||||
// template<class X> struct B : A<X> {
|
||||
// B() : x1(10), A<X>() {}
|
||||
// int x1;
|
||||
// };
|
||||
// B<int> x;
|
||||
// On seeing one dependent type, we should essentially exit this routine
|
||||
// while preserving user-declared initializer list. When this routine is
|
||||
// called during instantiatiation process, this routine will rebuild the
|
||||
// oderdered initializer list correctly.
|
||||
|
||||
// If we have a dependent base initialization, we can't determine the
|
||||
// association between initializers and bases; just dump the known
|
||||
// initializers into the list, and don't try to deal with other bases.
|
||||
for (unsigned i = 0; i < NumInitializers; i++) {
|
||||
CXXBaseOrMemberInitializer *Member = Initializers[i];
|
||||
if (Member->isBaseInitializer())
|
||||
AllToInit.push_back(Member);
|
||||
}
|
||||
} else {
|
||||
// Push virtual bases before others.
|
||||
for (CXXRecordDecl::base_class_iterator VBase =
|
||||
ClassDecl->vbases_begin(),
|
||||
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
|
||||
if (VBase->getType()->isDependentType())
|
||||
continue;
|
||||
if (CXXBaseOrMemberInitializer *Value =
|
||||
AllBaseFields.lookup(VBase->getType()->getAs<RecordType>()))
|
||||
AllToInit.push_back(Value);
|
||||
else {
|
||||
CXXRecordDecl *VBaseDecl =
|
||||
cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
|
||||
assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null");
|
||||
if (!VBaseDecl->getDefaultConstructor(Context))
|
||||
Bases.push_back(VBase);
|
||||
CXXBaseOrMemberInitializer *Member =
|
||||
new (Context) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0,
|
||||
VBaseDecl->getDefaultConstructor(Context),
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
AllToInit.push_back(Member);
|
||||
}
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::base_class_iterator Base =
|
||||
ClassDecl->bases_begin(),
|
||||
E = ClassDecl->bases_end(); Base != E; ++Base) {
|
||||
// Virtuals are in the virtual base list and already constructed.
|
||||
if (Base->isVirtual())
|
||||
continue;
|
||||
// Skip dependent types.
|
||||
if (Base->getType()->isDependentType())
|
||||
continue;
|
||||
if (CXXBaseOrMemberInitializer *Value =
|
||||
AllBaseFields.lookup(Base->getType()->getAs<RecordType>()))
|
||||
AllToInit.push_back(Value);
|
||||
else {
|
||||
CXXRecordDecl *BaseDecl =
|
||||
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
|
||||
if (!BaseDecl->getDefaultConstructor(Context))
|
||||
Bases.push_back(Base);
|
||||
CXXBaseOrMemberInitializer *Member =
|
||||
new (Context) CXXBaseOrMemberInitializer(Base->getType(), 0, 0,
|
||||
BaseDecl->getDefaultConstructor(Context),
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
AllToInit.push_back(Member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// non-static data members.
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
E = ClassDecl->field_end(); Field != E; ++Field) {
|
||||
if ((*Field)->isAnonymousStructOrUnion()) {
|
||||
if (const RecordType *FieldClassType =
|
||||
Field->getType()->getAs<RecordType>()) {
|
||||
CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||
for(RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
|
||||
EA = FieldClassDecl->field_end(); FA != EA; FA++) {
|
||||
if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) {
|
||||
// 'Member' is the anonymous union field and 'AnonUnionMember' is
|
||||
// set to the anonymous union data member used in the initializer
|
||||
// list.
|
||||
Value->setMember(*Field);
|
||||
Value->setAnonUnionMember(*FA);
|
||||
AllToInit.push_back(Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
|
||||
AllToInit.push_back(Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
QualType FT = Context.getBaseElementType((*Field)->getType());
|
||||
if (const RecordType* RT = FT->getAs<RecordType>()) {
|
||||
CXXConstructorDecl *Ctor =
|
||||
cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
|
||||
if (!Ctor && !FT->isDependentType())
|
||||
Fields.push_back(*Field);
|
||||
CXXBaseOrMemberInitializer *Member =
|
||||
new (Context) CXXBaseOrMemberInitializer((*Field), 0, 0,
|
||||
Ctor,
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
AllToInit.push_back(Member);
|
||||
if (FT.isConstQualified() && (!Ctor || Ctor->isTrivial())) {
|
||||
Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
|
||||
<< 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();
|
||||
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();
|
||||
Diag((*Field)->getLocation(), diag::note_declared_at);
|
||||
}
|
||||
}
|
||||
|
||||
NumInitializers = AllToInit.size();
|
||||
if (NumInitializers > 0) {
|
||||
Constructor->setNumBaseOrMemberInitializers(NumInitializers);
|
||||
CXXBaseOrMemberInitializer **baseOrMemberInitializers =
|
||||
new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
|
||||
|
||||
Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
|
||||
for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
|
||||
baseOrMemberInitializers[Idx] = AllToInit[Idx];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Sema::BuildBaseOrMemberInitializers(ASTContext &C,
|
||||
CXXConstructorDecl *Constructor,
|
||||
|
@ -898,9 +1072,8 @@ Sema::BuildBaseOrMemberInitializers(ASTContext &C,
|
|||
llvm::SmallVector<CXXBaseSpecifier *, 4>Bases;
|
||||
llvm::SmallVector<FieldDecl *, 4>Members;
|
||||
|
||||
Constructor->setBaseOrMemberInitializers(C,
|
||||
Initializers, NumInitializers,
|
||||
Bases, Members);
|
||||
setBaseOrMemberInitializers(Constructor,
|
||||
Initializers, NumInitializers, Bases, Members);
|
||||
for (unsigned int i = 0; i < Bases.size(); i++)
|
||||
Diag(Bases[i]->getSourceRange().getBegin(),
|
||||
diag::err_missing_default_constructor) << 0 << Bases[i]->getType();
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
struct A {
|
||||
A() : value(), cvalue() { } // expected-error {{cannot initialize the member to null in default constructor because reference member 'value' cannot be null-initialized}} \
|
||||
// expected-error {{constructor for 'struct A' must explicitly initialize the reference member 'value'}}
|
||||
int &value; // expected-note{{declared at}} {{expected-note{{declared at}}
|
||||
const int cvalue;
|
||||
};
|
||||
|
||||
struct B {
|
||||
};
|
||||
|
||||
struct X {
|
||||
X() { } // expected-error {{constructor for 'struct X' must explicitly initialize the reference member 'value'}} \
|
||||
// expected-error {{constructor for 'struct X' must explicitly initialize the const member 'cvalue'}} \
|
||||
// expected-error {{constructor for 'struct X' must explicitly initialize the reference member 'b'}} \
|
||||
// expected-error {{constructor for 'struct X' must explicitly initialize the const member 'cb'}}
|
||||
int &value; // expected-note{{declared at}}
|
||||
const int cvalue; // expected-note{{declared at}}
|
||||
B& b; // expected-note{{declared at}}
|
||||
const B cb; // expected-note{{declared at}}
|
||||
};
|
Загрузка…
Ссылка в новой задаче