summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp704
1 files changed, 352 insertions, 352 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 13a7ead..47df435 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1104,8 +1104,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// member.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
<< MemberOrBase << true << R.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
Diag(Member->getLocation(), diag::note_previous_decl)
<< Member->getDeclName();
@@ -1123,8 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// that base class.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
<< MemberOrBase << false << R.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
: VirtualBaseSpec;
@@ -1429,134 +1429,106 @@ bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
- bool IsImplicitConstructor,
bool AnyErrors) {
+ if (Constructor->isDependentContext()) {
+ // Just store the initializers as written, they will be checked during
+ // instantiation.
+ if (NumInitializers > 0) {
+ Constructor->setNumBaseOrMemberInitializers(NumInitializers);
+ CXXBaseOrMemberInitializer **baseOrMemberInitializers =
+ new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
+ memcpy(baseOrMemberInitializers, Initializers,
+ NumInitializers * sizeof(CXXBaseOrMemberInitializer*));
+ Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
+ }
+
+ return false;
+ }
+
// 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());
+ CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
+ if (!ClassDecl)
+ return true;
+
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
- bool HasDependentBaseInit = false;
bool HadError = false;
for (unsigned i = 0; i < NumInitializers; i++) {
CXXBaseOrMemberInitializer *Member = Initializers[i];
- if (Member->isBaseInitializer()) {
- if (Member->getBaseClass()->isDependentType())
- HasDependentBaseInit = true;
+
+ if (Member->isBaseInitializer())
AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
- } else {
+ 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
- // ordered 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 {
- llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
-
- // 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 if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, VBase);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
- HadError = true;
- continue;
- }
+ llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
- // Don't attach synthesized base initializers in a dependent
- // context; they'll be checked again at template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
-
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(VBase->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
- AllToInit.push_back(CXXBaseInit);
- }
- }
+ // Push virtual bases before others.
+ for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
- 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())
+ if (CXXBaseOrMemberInitializer *Value
+ = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ AllToInit.push_back(Value);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, VBase);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
+ HadError = true;
continue;
- if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
}
- else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, Base);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
- HadError = true;
- continue;
- }
-
- // Don't attach synthesized base initializers in a dependent
- // context; they'll be regenerated at template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(Base->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
- AllToInit.push_back(CXXBaseInit);
+ CXXBaseOrMemberInitializer *CXXBaseInit =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(VBase->getType(),
+ SourceLocation()),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(CXXBaseInit);
+ }
+ }
+
+ 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;
+
+ if (CXXBaseOrMemberInitializer *Value
+ = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
+ AllToInit.push_back(Value);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, Base);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
+ HadError = true;
+ continue;
}
+
+ CXXBaseOrMemberInitializer *CXXBaseInit =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(Base->getType(),
+ SourceLocation()),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(CXXBaseInit);
}
}
@@ -1624,14 +1596,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
}
else if (FT->isReferenceType()) {
Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
<< 0 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
HadError = true;
}
else if (FT.isConstQualified()) {
Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
<< 1 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
HadError = true;
@@ -1665,121 +1637,70 @@ 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(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.
- if (Member->isMemberInitializer()) {
- FieldDecl *Field = Member->getMember();
-
- // 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())
- Field = Member->getAnonUnionMember();
- if (Field->getDeclContext()->isRecord()) {
- RecordDecl *RD = cast<RecordDecl>(Field->getDeclContext());
- if (RD->isAnonymousStructOrUnion())
- return static_cast<void *>(RD);
- }
- return static_cast<void *>(Field);
- }
-
- return GetKeyForBase(QualType(Member->getBaseClass(), 0));
-}
-
-/// ActOnMemInitializers - Handle the member initializers for a constructor.
-void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
- SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits,
- bool AnyErrors) {
- if (!ConstructorDecl)
- return;
+ FieldDecl *Field = Member->getMember();
- AdjustDeclIfTemplate(ConstructorDecl);
-
- CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
-
- if (!Constructor) {
- Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
- return;
- }
-
- if (!Constructor->isDependentContext()) {
- llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members;
- bool err = false;
- for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member =
- static_cast<CXXBaseOrMemberInitializer*>(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;
- }
-
- if (err)
- return;
- }
+ // 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())
+ Field = Member->getAnonUnionMember();
+
+ // If the field is a member of an anonymous union, we use record decl of the
+ // union as the key.
+ RecordDecl *RD = Field->getParent();
+ if (RD->isAnonymousStructOrUnion() && RD->isUnion())
+ return static_cast<void *>(RD);
- SetBaseOrMemberInitializers(Constructor,
- reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits, false, AnyErrors);
+ return static_cast<void *>(Field);
+}
+static void
+DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
+ const CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **MemInits,
+ unsigned NumMemInits) {
if (Constructor->isDependentContext())
return;
- if (Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
+ if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
Diagnostic::Ignored &&
- Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
+ SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
Diagnostic::Ignored)
return;
-
+
// Also issue warning if order of ctor-initializer list does not match order
// of 1) base class declarations and 2) order of non-static data members.
llvm::SmallVector<const void*, 32> AllBaseOrMembers;
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ const CXXRecordDecl *ClassDecl = Constructor->getParent();
+
// Push virtual bases before others.
- for (CXXRecordDecl::base_class_iterator VBase =
+ 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_iterator Base = ClassDecl->bases_begin(),
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
// Virtuals are alread in the virtual base list and are constructed
// 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(),
@@ -1790,9 +1711,8 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
int curIndex = 0;
CXXBaseOrMemberInitializer *PrevMember = 0;
for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member =
- static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
- void *MemberInCtorList = GetKeyForMember(Member, true);
+ CXXBaseOrMemberInitializer *Member = MemInits[i];
+ void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true);
for (; curIndex < Last; curIndex++)
if (MemberInCtorList == AllBaseOrMembers[curIndex])
@@ -1804,23 +1724,23 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
if (PrevMember->isBaseInitializer()) {
// Diagnostics is for an initialized base class.
Type *BaseClass = PrevMember->getBaseClass();
- Diag(PrevMember->getSourceLocation(),
- diag::warn_base_initialized)
+ SemaRef.Diag(PrevMember->getSourceLocation(),
+ diag::warn_base_initialized)
<< QualType(BaseClass, 0);
} else {
FieldDecl *Field = PrevMember->getMember();
- Diag(PrevMember->getSourceLocation(),
- diag::warn_field_initialized)
+ SemaRef.Diag(PrevMember->getSourceLocation(),
+ diag::warn_field_initialized)
<< Field->getNameAsString();
}
// Also the note!
if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 0
+ SemaRef.Diag(Member->getSourceLocation(),
+ diag::note_fieldorbase_initialized_here) << 0
<< Field->getNameAsString();
else {
Type *BaseClass = Member->getBaseClass();
- Diag(Member->getSourceLocation(),
+ SemaRef.Diag(Member->getSourceLocation(),
diag::note_fieldorbase_initialized_here) << 1
<< QualType(BaseClass, 0);
}
@@ -1832,6 +1752,64 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
}
}
+/// ActOnMemInitializers - Handle the member initializers for a constructor.
+void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+ SourceLocation ColonLoc,
+ MemInitTy **meminits, unsigned NumMemInits,
+ bool AnyErrors) {
+ if (!ConstructorDecl)
+ return;
+
+ AdjustDeclIfTemplate(ConstructorDecl);
+
+ CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
+
+ if (!Constructor) {
+ Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
+ return;
+ }
+
+ CXXBaseOrMemberInitializer **MemInits =
+ reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits);
+
+ llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
+ bool HadError = false;
+ for (unsigned i = 0; i < NumMemInits; i++) {
+ CXXBaseOrMemberInitializer *Member = MemInits[i];
+
+ void *KeyToMember = GetKeyForMember(Context, 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;
+ HadError = true;
+ }
+
+ if (HadError)
+ return;
+
+ DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits);
+
+ SetBaseOrMemberInitializers(Constructor, MemInits, NumMemInits, AnyErrors);
+}
+
void
Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXRecordDecl *ClassDecl) {
@@ -1861,7 +1839,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
CheckDestructorAccess(Field->getLocation(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_field)
+ PDiag(diag::err_access_dtor_field)
<< Field->getDeclName()
<< FieldType);
@@ -1889,7 +1867,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// FIXME: caret should be on the start of the class name
CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_base)
+ PDiag(diag::err_access_dtor_base)
<< Base->getType()
<< Base->getSourceRange());
@@ -1914,7 +1892,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_vbase)
+ PDiag(diag::err_access_dtor_vbase)
<< VBase->getType());
MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
@@ -1925,94 +1903,11 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
if (!CDtorDecl)
return;
- AdjustDeclIfTemplate(CDtorDecl);
-
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
- SetBaseOrMemberInitializers(Constructor, 0, 0, false, false);
-}
-
-namespace {
- /// PureVirtualMethodCollector - traverses a class and its superclasses
- /// and determines if it has any pure virtual methods.
- class PureVirtualMethodCollector {
- ASTContext &Context;
-
- public:
- typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList;
-
- private:
- MethodList Methods;
-
- void Collect(const CXXRecordDecl* RD, MethodList& Methods);
-
- public:
- PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
- : Context(Ctx) {
-
- MethodList List;
- Collect(RD, List);
-
- // Copy the temporary list to methods, and make sure to ignore any
- // null entries.
- for (size_t i = 0, e = List.size(); i != e; ++i) {
- if (List[i])
- Methods.push_back(List[i]);
- }
- }
-
- bool empty() const { return Methods.empty(); }
-
- MethodList::const_iterator methods_begin() { return Methods.begin(); }
- MethodList::const_iterator methods_end() { return Methods.end(); }
- };
-
- void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
- MethodList& Methods) {
- // First, collect the pure virtual methods for the base classes.
- for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
- BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
- if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (BaseDecl && BaseDecl->isAbstract())
- Collect(BaseDecl, Methods);
- }
- }
-
- // Next, zero out any pure virtual methods that this class overrides.
- typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy;
-
- MethodSetTy OverriddenMethods;
- size_t MethodsSize = Methods.size();
-
- for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
- i != e; ++i) {
- // Traverse the record, looking for methods.
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
- // If the method is pure virtual, add it to the methods vector.
- if (MD->isPure())
- Methods.push_back(MD);
-
- // Record all the overridden methods in our set.
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods(); I != E; ++I) {
- // Keep track of the overridden methods.
- OverriddenMethods.insert(*I);
- }
- }
- }
-
- // Now go through the methods and zero out all the ones we know are
- // overridden.
- for (size_t i = 0, e = MethodsSize; i != e; ++i) {
- if (OverriddenMethods.count(Methods[i]))
- Methods[i] = 0;
- }
-
- }
+ SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false);
}
-
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
unsigned DiagID, AbstractDiagSelID SelID,
const CXXRecordDecl *CurrentRD) {
@@ -2066,14 +1961,32 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD))
return true;
- PureVirtualMethodCollector Collector(Context, RD);
+ CXXFinalOverriderMap FinalOverriders;
+ RD->getFinalOverriders(FinalOverriders);
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+ MEnd = FinalOverriders.end();
+ M != MEnd;
+ ++M) {
+ for (OverridingMethods::iterator SO = M->second.begin(),
+ SOEnd = M->second.end();
+ SO != SOEnd; ++SO) {
+ // C++ [class.abstract]p4:
+ // A class is abstract if it contains or inherits at least one
+ // pure virtual function for which the final overrider is pure
+ // virtual.
+
+ //
+ if (SO->second.size() != 1)
+ continue;
- for (PureVirtualMethodCollector::MethodList::const_iterator I =
- Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
+ if (!SO->second.front().Method->isPure())
+ continue;
- Diag(MD->getLocation(), diag::note_pure_virtual_function) <<
- MD->getDeclName();
+ Diag(SO->second.front().Method->getLocation(),
+ diag::note_pure_virtual_function)
+ << SO->second.front().Method->getDeclName();
+ }
}
if (!PureVirtualClassDiagSet)
@@ -2162,22 +2075,79 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I)
Convs->setAccess(I, (*I)->getAccess());
- if (!Record->isAbstract()) {
- // Collect all the pure virtual methods and see if this is an abstract
- // class after all.
- PureVirtualMethodCollector Collector(Context, Record);
- if (!Collector.empty())
- Record->setAbstract(true);
+ // Determine whether we need to check for final overriders. We do
+ // this either when there are virtual base classes (in which case we
+ // may end up finding multiple final overriders for a given virtual
+ // function) or any of the base classes is abstract (in which case
+ // we might detect that this class is abstract).
+ bool CheckFinalOverriders = false;
+ if (Record->isPolymorphic() && !Record->isInvalidDecl() &&
+ !Record->isDependentType()) {
+ if (Record->getNumVBases())
+ CheckFinalOverriders = true;
+ else if (!Record->isAbstract()) {
+ for (CXXRecordDecl::base_class_const_iterator B = Record->bases_begin(),
+ BEnd = Record->bases_end();
+ B != BEnd; ++B) {
+ CXXRecordDecl *BaseDecl
+ = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl());
+ if (BaseDecl->isAbstract()) {
+ CheckFinalOverriders = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (CheckFinalOverriders) {
+ CXXFinalOverriderMap FinalOverriders;
+ Record->getFinalOverriders(FinalOverriders);
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+ MEnd = FinalOverriders.end();
+ M != MEnd; ++M) {
+ for (OverridingMethods::iterator SO = M->second.begin(),
+ SOEnd = M->second.end();
+ SO != SOEnd; ++SO) {
+ assert(SO->second.size() > 0 &&
+ "All virtual functions have overridding virtual functions");
+ if (SO->second.size() == 1) {
+ // C++ [class.abstract]p4:
+ // A class is abstract if it contains or inherits at least one
+ // pure virtual function for which the final overrider is pure
+ // virtual.
+ if (SO->second.front().Method->isPure())
+ Record->setAbstract(true);
+ continue;
+ }
+
+ // C++ [class.virtual]p2:
+ // In a derived class, if a virtual member function of a base
+ // class subobject has more than one final overrider the
+ // program is ill-formed.
+ Diag(Record->getLocation(), diag::err_multiple_final_overriders)
+ << (NamedDecl *)M->first << Record;
+ Diag(M->first->getLocation(), diag::note_overridden_virtual_function);
+ for (OverridingMethods::overriding_iterator OM = SO->second.begin(),
+ OMEnd = SO->second.end();
+ OM != OMEnd; ++OM)
+ Diag(OM->Method->getLocation(), diag::note_final_overrider)
+ << (NamedDecl *)M->first << OM->Method->getParent();
+
+ Record->setInvalidDecl();
+ }
+ }
}
- if (Record->isAbstract())
+ if (Record->isAbstract() && !Record->isInvalidDecl())
(void)AbstractClassUsageDiagnoser(*this, Record);
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
- SourceLocation RBrac) {
+ SourceLocation RBrac,
+ AttributeList *AttrList) {
if (!TagDecl)
return;
@@ -2185,7 +2155,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
ActOnFields(S, RLoc, TagDecl,
(DeclPtrTy*)FieldCollector->getCurFields(),
- FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
+ FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList);
CheckCompletedCXXClass(
dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
@@ -2218,8 +2188,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
/*FIXME*/false, false,
- 0, 0, false,
- CC_Default),
+ 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
@@ -2293,8 +2263,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
&ArgType, 1,
false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default),
+ false, 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
@@ -2382,8 +2352,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(RetType, &ArgType, 1,
false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default),
+ false, 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
@@ -2412,8 +2382,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType Ty = Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default);
+ false, 0, 0, FunctionType::ExtInfo());
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
@@ -2586,8 +2555,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
Proto->hasAnyExceptionSpec(),
Proto->getNumExceptions(),
Proto->exception_begin(),
- Proto->getNoReturnAttr(),
- Proto->getCallConv());
+ Proto->getExtInfo());
}
/// CheckConstructor - Checks a fully-formed constructor for
@@ -2615,7 +2583,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
Diag(ParamLoc, diag::err_constructor_byvalue_arg)
- << CodeModificationHint::CreateInsertion(ParamLoc, " const &");
+ << FixItHint::CreateInsertion(ParamLoc, " const &");
// FIXME: Rather that making the constructor invalid, we should endeavor
// to fix the type.
@@ -2746,7 +2714,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
// will put in a result type of "int" when none was specified.
// FIXME: Exceptions!
return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0,
- false, false, 0, 0, false, CC_Default);
+ false, false, 0, 0, FunctionType::ExtInfo());
}
/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
@@ -2822,8 +2790,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Proto->hasAnyExceptionSpec(),
Proto->getNumExceptions(),
Proto->exception_begin(),
- Proto->getNoReturnAttr(),
- Proto->getCallConv());
+ Proto->getExtInfo());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
@@ -2962,7 +2929,6 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
} else {
// Anonymous namespaces.
assert(Namespc->isAnonymousNamespace());
- CurContext->addDecl(Namespc);
// Link the anonymous namespace into its parent.
NamespaceDecl *PrevDecl;
@@ -2984,6 +2950,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
PrevDecl->setNextNamespace(Namespc);
}
+ CurContext->addDecl(Namespc);
+
// C++ [namespace.unnamed]p1. An unnamed-namespace-definition
// behaves as if it were replaced by
// namespace unique { /* empty body */ }
@@ -3160,8 +3128,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
UsingLoc = Name.getSourceRange().getBegin();
Diag(UsingLoc, diag::warn_access_decl_deprecated)
- << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(),
- "using ");
+ << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using ");
}
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
@@ -3330,6 +3297,11 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
CurContext->addDecl(Shadow);
Shadow->setAccess(UD->getAccess());
+ // Register it as a conversion if appropriate.
+ if (Shadow->getDeclName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName)
+ cast<CXXRecordDecl>(CurContext)->addConversionFunction(Shadow);
+
if (Orig->isInvalidDecl() || UD->isInvalidDecl())
Shadow->setInvalidDecl();
@@ -3364,6 +3336,10 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
/// decl structures are (very reasonably) not designed for removal.
/// (2) avoids this but is very fiddly and phase-dependent.
void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
+ if (Shadow->getDeclName().getNameKind() ==
+ DeclarationName::CXXConversionFunctionName)
+ cast<CXXRecordDecl>(Shadow->getDeclContext())->removeConversion(Shadow);
+
// Remove it from the DeclContext...
Shadow->getDeclContext()->removeDecl(Shadow);
@@ -3377,7 +3353,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
Shadow->getUsingDecl()->removeShadowDecl(Shadow);
// TODO: complain somehow if Shadow was used. It shouldn't
- // be possible for this to happen, because
+ // be possible for this to happen, because...?
}
/// Builds a using declaration.
@@ -3738,8 +3714,10 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
// namespace, so don't create a new one.
+ // FIXME: At some point, we'll want to create the (redundant)
+ // declaration to maintain better source information.
if (!R.isAmbiguous() && !R.empty() &&
- AD->getNamespace() == getNamespaceDecl(R.getFoundDecl()))
+ AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl())))
return DeclPtrTy();
}
@@ -3780,7 +3758,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
DeclContext *PreviousContext = CurContext;
CurContext = Constructor;
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) {
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
@@ -3847,7 +3825,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
BaseClassDecl)) {
CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
BaseAssignOpMethod,
- PartialDiagnostic(diag::err_access_assign_base)
+ PDiag(diag::err_access_assign_base)
<< Base->getType());
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
@@ -3866,7 +3844,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
FieldClassDecl)) {
CheckDirectMemberAccess(Field->getLocation(),
FieldAssignOpMethod,
- PartialDiagnostic(diag::err_access_assign_field)
+ PDiag(diag::err_access_assign_field)
<< Field->getDeclName() << Field->getType());
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
@@ -3948,7 +3926,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
BaseClassDecl->getCopyConstructor(Context, TypeQuals)) {
CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
BaseCopyCtor,
- PartialDiagnostic(diag::err_access_copy_base)
+ PDiag(diag::err_access_copy_base)
<< Base->getType());
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
@@ -3967,7 +3945,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
FieldClassDecl->getCopyConstructor(Context, TypeQuals)) {
CheckDirectMemberAccess(Field->getLocation(),
FieldCopyCtor,
- PartialDiagnostic(diag::err_access_copy_field)
+ PDiag(diag::err_access_copy_field)
<< Field->getDeclName() << Field->getType());
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
@@ -4062,7 +4040,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
CheckDestructorAccess(VD->getLocation(), Destructor,
- PartialDiagnostic(diag::err_access_dtor_var)
+ PDiag(diag::err_access_dtor_var)
<< VD->getDeclName()
<< VD->getType());
}
@@ -4408,16 +4386,18 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (Context.getCanonicalType(T2) == Context.OverloadTy) {
+ DeclAccessPair Found;
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
- ICS != 0);
+ ICS != 0, Found);
if (Fn) {
// Since we're performing this reference-initialization for
// real, update the initializer with the resulting function.
if (!ICS) {
if (DiagnoseUseOfDecl(Fn, DeclLoc))
- return true;
+ return true;
- Init = FixOverloadedFunctionReference(Init, Fn);
+ CheckAddressOfMemberAccess(Init, Found);
+ Init = FixOverloadedFunctionReference(Init, Found, Fn);
}
T2 = Fn->getType();
@@ -5378,7 +5358,8 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend templates because ActOnTag never produces a ClassTemplateDecl
// for a TUK_Friend.
Declarator TheDeclarator(DS, Declarator::MemberContext);
- QualType T = GetTypeForDeclarator(TheDeclarator, S);
+ TypeSourceInfo *TSI;
+ QualType T = GetTypeForDeclarator(TheDeclarator, S, &TSI);
if (TheDeclarator.isInvalidType())
return DeclPtrTy();
@@ -5396,7 +5377,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
//
// FIXME: handle "template <> friend class A<T>;", which
// is possibly well-formed? Who even knows?
- if (TempParams.size() && !isa<ElaboratedType>(T)) {
+ if (TempParams.size() && !T->isElaboratedTypeSpecifier()) {
Diag(Loc, diag::err_tagless_friend_type_template)
<< DS.getSourceRange();
return DeclPtrTy();
@@ -5408,7 +5389,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// * The class-key of the elaborated-type-specifier is required.
// This is one of the rare places in Clang where it's legitimate to
// ask about the "spelling" of the type.
- if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) {
+ if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
// If we evaluated the type to a record type, suggest putting
// a tag in front.
if (const RecordType *RT = T->getAs<RecordType>()) {
@@ -5420,8 +5401,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
<< (unsigned) RD->getTagKind()
<< T
<< SourceRange(DS.getFriendSpecLoc())
- << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
- InsertionText);
+ << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText);
return DeclPtrTy();
}else {
Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
@@ -5443,16 +5423,20 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// deadline. It's also a very silly restriction that seriously
// affects inner classes and which nobody else seems to implement;
// thus we never diagnose it, not even in -pedantic.
+ //
+ // But note that we could warn about it: it's always useless to
+ // friend one of your own members (it's not, however, worthless to
+ // friend a member of an arbitrary specialization of your template).
Decl *D;
if (TempParams.size())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
TempParams.size(),
(TemplateParameterList**) TempParams.release(),
- T.getTypePtr(),
+ TSI,
DS.getFriendSpecLoc());
else
- D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(),
+ D = FriendDecl::Create(Context, CurContext, Loc, TSI,
DS.getFriendSpecLoc());
D->setAccess(AS_public);
CurContext->addDecl(D);
@@ -5889,7 +5873,7 @@ static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) {
break;
case TSK_ExplicitInstantiationDeclaration:
- return true; //FIXME: This looks wrong.
+ return false;
case TSK_ExplicitInstantiationDefinition:
// This is method of a explicit instantiation; mark all of the virtual
@@ -5945,7 +5929,8 @@ bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
return true;
}
-void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
+void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
+ const CXXRecordDecl *RD) {
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
e = RD->method_end(); i != e; ++i) {
CXXMethodDecl *MD = *i;
@@ -5955,4 +5940,19 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
if (MD->isVirtual() && !MD->isPure())
MarkDeclarationReferenced(Loc, MD);
}
+
+ // Only classes that have virtual bases need a VTT.
+ if (RD->getNumVBases() == 0)
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual())
+ continue;
+ if (Base->getNumVBases() == 0)
+ continue;
+ MarkVirtualMembersReferenced(Loc, Base);
+ }
}
OpenPOWER on IntegriCloud