Diagnose multiple base and member initializers in class templates.
llvm-svn: 100179
This commit is contained in:
parent
3c54edf9b3
commit
7b3f2788a1
|
@ -1430,12 +1430,9 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
|||
CXXBaseOrMemberInitializer **Initializers,
|
||||
unsigned NumInitializers,
|
||||
bool AnyErrors) {
|
||||
// assert((Constructor->isImplicit() == 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())->getDefinition();
|
||||
CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
|
||||
if (!ClassDecl)
|
||||
return true;
|
||||
|
||||
|
@ -1670,18 +1667,15 @@ static void *GetKeyForTopLevelField(FieldDecl *Field) {
|
|||
return static_cast<void *>(Field);
|
||||
}
|
||||
|
||||
static void *GetKeyForBase(QualType BaseType) {
|
||||
if (const RecordType *RT = BaseType->getAs<RecordType>())
|
||||
return (void *)RT;
|
||||
|
||||
assert(0 && "Unexpected base type!");
|
||||
return 0;
|
||||
static void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
|
||||
return Context.getCanonicalType(BaseType).getTypePtr();
|
||||
}
|
||||
|
||||
static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
|
||||
static void *GetKeyForMember(ASTContext &Context,
|
||||
CXXBaseOrMemberInitializer *Member,
|
||||
bool MemberMaybeAnon = false) {
|
||||
if (!Member->isMemberInitializer())
|
||||
return GetKeyForBase(QualType(Member->getBaseClass(), 0));
|
||||
return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
|
||||
|
||||
// For fields injected into the class via declaration of an anonymous union,
|
||||
// use its anonymous union class declaration as the unique key.
|
||||
|
@ -1726,7 +1720,8 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
|
|||
for (CXXRecordDecl::base_class_const_iterator VBase =
|
||||
ClassDecl->vbases_begin(),
|
||||
E = ClassDecl->vbases_end(); VBase != E; ++VBase)
|
||||
AllBaseOrMembers.push_back(GetKeyForBase(VBase->getType()));
|
||||
AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
|
||||
VBase->getType()));
|
||||
|
||||
for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
|
||||
E = ClassDecl->bases_end(); Base != E; ++Base) {
|
||||
|
@ -1734,7 +1729,8 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
|
|||
// first.
|
||||
if (Base->isVirtual())
|
||||
continue;
|
||||
AllBaseOrMembers.push_back(GetKeyForBase(Base->getType()));
|
||||
AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
|
||||
Base->getType()));
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
|
@ -1746,7 +1742,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
|
|||
CXXBaseOrMemberInitializer *PrevMember = 0;
|
||||
for (unsigned i = 0; i < NumMemInits; i++) {
|
||||
CXXBaseOrMemberInitializer *Member = MemInits[i];
|
||||
void *MemberInCtorList = GetKeyForMember(Member, true);
|
||||
void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true);
|
||||
|
||||
for (; curIndex < Last; curIndex++)
|
||||
if (MemberInCtorList == AllBaseOrMembers[curIndex])
|
||||
|
@ -1807,40 +1803,38 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
|
|||
CXXBaseOrMemberInitializer **MemInits =
|
||||
reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits);
|
||||
|
||||
if (!Constructor->isDependentContext()) {
|
||||
llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
|
||||
bool err = false;
|
||||
for (unsigned i = 0; i < NumMemInits; i++) {
|
||||
CXXBaseOrMemberInitializer *Member = MemInits[i];
|
||||
llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
|
||||
bool HadError = false;
|
||||
for (unsigned i = 0; i < NumMemInits; i++) {
|
||||
CXXBaseOrMemberInitializer *Member = MemInits[i];
|
||||
|
||||
void *KeyToMember = GetKeyForMember(Member);
|
||||
CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
|
||||
if (!PrevMember) {
|
||||
PrevMember = Member;
|
||||
continue;
|
||||
}
|
||||
if (FieldDecl *Field = Member->getMember())
|
||||
Diag(Member->getSourceLocation(),
|
||||
diag::error_multiple_mem_initialization)
|
||||
<< Field->getNameAsString()
|
||||
<< Member->getSourceRange();
|
||||
else {
|
||||
Type *BaseClass = Member->getBaseClass();
|
||||
assert(BaseClass && "ActOnMemInitializers - neither field or base");
|
||||
Diag(Member->getSourceLocation(),
|
||||
diag::error_multiple_base_initialization)
|
||||
<< QualType(BaseClass, 0)
|
||||
<< Member->getSourceRange();
|
||||
}
|
||||
Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
|
||||
<< 0;
|
||||
err = true;
|
||||
void *KeyToMember = GetKeyForMember(Context, Member);
|
||||
CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
|
||||
if (!PrevMember) {
|
||||
PrevMember = Member;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (err)
|
||||
return;
|
||||
if (FieldDecl *Field = Member->getMember())
|
||||
Diag(Member->getSourceLocation(),
|
||||
diag::error_multiple_mem_initialization)
|
||||
<< Field->getNameAsString()
|
||||
<< Member->getSourceRange();
|
||||
else {
|
||||
Type *BaseClass = Member->getBaseClass();
|
||||
assert(BaseClass && "ActOnMemInitializers - neither field or base");
|
||||
Diag(Member->getSourceLocation(),
|
||||
diag::error_multiple_base_initialization)
|
||||
<< QualType(BaseClass, 0)
|
||||
<< Member->getSourceRange();
|
||||
}
|
||||
Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
|
||||
<< 0;
|
||||
HadError = true;
|
||||
}
|
||||
|
||||
if (HadError)
|
||||
return;
|
||||
|
||||
DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits);
|
||||
|
||||
SetBaseOrMemberInitializers(Constructor, MemInits, NumMemInits, AnyErrors);
|
||||
|
|
|
@ -26,3 +26,28 @@ struct A {
|
|||
};
|
||||
|
||||
A::A() : a(10), b(20) { }
|
||||
|
||||
namespace Test1 {
|
||||
template<typename T> struct A {};
|
||||
template<typename T> struct B : A<T> {
|
||||
|
||||
B() : A<T>(), // expected-note {{previous initialization is here}}
|
||||
A<T>() { } // expected-error {{multiple initializations given for base 'A<T>'}}
|
||||
};
|
||||
}
|
||||
|
||||
namespace Test2 {
|
||||
template<typename T> struct A : T {
|
||||
A() : T(), // expected-note {{previous initialization is here}}
|
||||
T() { } // expected-error {{multiple initializations given for base 'T'}}
|
||||
};
|
||||
}
|
||||
|
||||
namespace Test3 {
|
||||
template<typename T> struct A {
|
||||
T t;
|
||||
|
||||
A() : t(1), // expected-note {{previous initialization is here}}
|
||||
t(2) { } // expected-error {{multiple initializations given for non-static member 't'}}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue