aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTConsumer.h12
-rw-r--r--lib/CodeGen/CGVTables.cpp54
-rw-r--r--lib/CodeGen/CGVTables.h10
-rw-r--r--lib/CodeGen/CodeGenModule.cpp10
-rw-r--r--lib/CodeGen/CodeGenModule.h2
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp7
-rw-r--r--lib/Frontend/CodeGenAction.cpp4
-rw-r--r--lib/Sema/Sema.cpp18
-rw-r--r--lib/Sema/Sema.h43
-rw-r--r--lib/Sema/SemaCXXCast.cpp8
-rw-r--r--lib/Sema/SemaDecl.cpp47
-rw-r--r--lib/Sema/SemaDeclCXX.cpp198
-rw-r--r--lib/Sema/SemaExpr.cpp8
-rw-r--r--lib/Sema/SemaExprCXX.cpp27
-rw-r--r--lib/Sema/SemaInit.cpp9
-rw-r--r--lib/Sema/SemaTemplate.cpp8
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp30
-rw-r--r--test/CodeGenCXX/cxx-apple-kext.cpp2
-rw-r--r--test/CodeGenCXX/rtti-linkage.cpp65
-rw-r--r--test/CodeGenCXX/thunks.cpp2
-rw-r--r--test/CodeGenCXX/virtual-base-destructor-call.cpp1
-rw-r--r--test/CodeGenCXX/virtual-functions-incomplete-types.cpp2
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp1672
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp76
-rw-r--r--test/SemaCXX/implicit-virtual-member-functions.cpp4
-rw-r--r--test/SemaCXX/virtual-member-functions-key-function.cpp10
-rw-r--r--test/SemaCXX/warn-weak-vtables.cpp10
-rw-r--r--test/SemaTemplate/virtual-member-functions.cpp39
28 files changed, 1266 insertions, 1112 deletions
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index 53bb785c49..06113954fc 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -16,6 +16,7 @@
namespace clang {
class ASTContext;
+ class CXXRecordDecl;
class DeclGroupRef;
class TagDecl;
class HandleTagDeclDefinition;
@@ -68,6 +69,17 @@ public:
/// modified by the introduction of an implicit zero initializer.
virtual void CompleteTentativeDefinition(VarDecl *D) {}
+ /// \brief Callback involved at the end of a translation unit to
+ /// notify the consumer that a vtable for the given C++ class is
+ /// required.
+ ///
+ /// \param RD The class whose vtable was used.
+ ///
+ /// \param DefinitionRequired Whether a definition of this vtable is
+ /// required in this translation unit; otherwise, it is only needed if
+ /// it was actually used.
+ virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
+
/// PrintStats - If desired, print any statistics.
virtual void PrintStats() {}
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index df0f641a50..368e2483c8 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -2788,7 +2788,13 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
// Check if we've computed this information before.
if (LayoutData)
return;
-
+
+ // We may need to generate a definition for this vtable.
+ if (!isKeyFunctionInAnotherTU(CGM.getContext(), RD) &&
+ RD->getTemplateSpecializationKind()
+ != TSK_ExplicitInstantiationDeclaration)
+ CGM.DeferredVTables.push_back(RD);
+
VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
// Add the VTable layout.
@@ -3119,49 +3125,3 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
DC->getParent()->isTranslationUnit())
CGM.EmitFundamentalRTTIDescriptors();
}
-
-void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const CXXRecordDecl *RD = MD->getParent();
-
- // If the class doesn't have a vtable we don't need to emit one.
- if (!RD->isDynamicClass())
- return;
-
- // Check if we need to emit thunks for this function.
- if (MD->isVirtual())
- EmitThunks(GD);
-
- // Get the key function.
- const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
-
- TemplateSpecializationKind RDKind = RD->getTemplateSpecializationKind();
- TemplateSpecializationKind MDKind = MD->getTemplateSpecializationKind();
-
- if (KeyFunction) {
- // We don't have the right key function.
- if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
- return;
- } else {
- // If we have no key function and this is a explicit instantiation
- // declaration, we will produce a vtable at the explicit instantiation. We
- // don't need one here.
- if (RDKind == clang::TSK_ExplicitInstantiationDeclaration)
- return;
-
- // If this is an explicit instantiation of a method, we don't need a vtable.
- // Since we have no key function, we will emit the vtable when we see
- // a use, and just defining a function is not an use.
- if (RDKind == TSK_ImplicitInstantiation &&
- MDKind == TSK_ExplicitInstantiationDefinition)
- return;
- }
-
- if (VTables.count(RD))
- return;
-
- if (RDKind == TSK_ImplicitInstantiation)
- CGM.DeferredVTables.push_back(RD);
- else
- GenerateClassData(CGM.getVTableLinkage(RD), RD);
-}
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index 6c18ca83f0..e55377f2fa 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -272,9 +272,6 @@ class CodeGenVTables {
/// EmitThunk - Emit a single thunk.
void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk);
- /// EmitThunks - Emit the associated thunks for the given global decl.
- void EmitThunks(GlobalDecl GD);
-
/// ComputeVTableRelatedInformation - Compute and store all vtable related
/// information (vtable layout, vbase offset offsets, thunks etc) for the
/// given record decl.
@@ -349,11 +346,10 @@ public:
VTableAddressPointsMapTy& AddressPoints);
llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD);
-
- // EmitVTableRelatedData - Will emit any thunks that the global decl might
- // have, as well as the vtable itself if the global decl is the key function.
- void EmitVTableRelatedData(GlobalDecl GD);
+ /// EmitThunks - Emit the associated thunks for the given global decl.
+ void EmitThunks(GlobalDecl GD);
+
/// GenerateClassData - Generate all the class data required to be generated
/// upon definition of a KeyFunction. This includes the vtable, the
/// rtti data structure and the VTT.
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 6cbc3f67c2..6dd16e73b4 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -727,8 +727,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
Context.getSourceManager(),
"Generating code for declaration");
- if (isa<CXXMethodDecl>(D))
- getVTables().EmitVTableRelatedData(GD);
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isVirtual())
+ getVTables().EmitThunks(GD);
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
return EmitCXXConstructor(CD, GD.getCtorType());
@@ -984,6 +985,11 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
EmitGlobalVarDefinition(D);
}
+void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) {
+ if (DefinitionRequired)
+ getVTables().GenerateClassData(getVTableLinkage(Class), Class);
+}
+
llvm::GlobalVariable::LinkageTypes
CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 93d8ddf3e4..0e4f4a932e 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -422,6 +422,8 @@ public:
void EmitTentativeDefinition(const VarDecl *D);
+ void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired);
+
enum GVALinkage {
GVA_Internal,
GVA_C99Inline,
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 1e1edc1c48..9905ca6f1d 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -89,6 +89,13 @@ namespace {
Builder->EmitTentativeDefinition(D);
}
+
+ virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ Builder->EmitVTable(RD, DefinitionRequired);
+ }
};
}
diff --git a/lib/Frontend/CodeGenAction.cpp b/lib/Frontend/CodeGenAction.cpp
index 79d7d5f4c2..86005f280a 100644
--- a/lib/Frontend/CodeGenAction.cpp
+++ b/lib/Frontend/CodeGenAction.cpp
@@ -180,6 +180,10 @@ namespace {
Gen->CompleteTentativeDefinition(D);
}
+ virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {
+ Gen->HandleVTable(RD, DefinitionRequired);
+ }
+
static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
unsigned LocCookie) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 91effa44b2..569de3203a 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -164,6 +164,18 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
}
}
+ // If this is a derived-to-base cast to a through a virtual base, we
+ // need a vtable.
+ if (Kind == CastExpr::CK_DerivedToBase &&
+ BasePathInvolvesVirtualBase(BasePath)) {
+ QualType T = Expr->getType();
+ if (const PointerType *Pointer = T->getAs<PointerType>())
+ T = Pointer->getPointeeType();
+ if (const RecordType *RecordTy = T->getAs<RecordType>())
+ MarkVTableUsed(Expr->getLocStart(),
+ cast<CXXRecordDecl>(RecordTy->getDecl()));
+ }
+
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
if (ImpCast->getCastKind() == Kind && BasePath.empty()) {
ImpCast->setType(Ty);
@@ -199,10 +211,10 @@ void Sema::ActOnEndOfTranslationUnit() {
// template instantiations earlier.
PerformPendingImplicitInstantiations();
- /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking
- /// any virtual member functions it might lead to more pending template
+ /// If DefinedUsedVTables ends up marking any virtual member
+ /// functions it might lead to more pending template
/// instantiations, which is why we need to loop here.
- if (!ProcessPendingClassesWithUnmarkedVirtualMembers())
+ if (!DefineUsedVTables())
break;
}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 9d811a4dbe..4ef5ebe20a 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2560,27 +2560,38 @@ public:
void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc,
CXXRecordDecl *Record);
- /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual
- /// members need to be marked as referenced at the end of the translation
- /// unit. It will contain polymorphic classes that do not have a key
- /// function or have a key function that has been defined.
- llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 4>
- ClassesWithUnmarkedVirtualMembers;
-
- /// MaybeMarkVirtualMembersReferenced - If the passed in method is the
- /// key function of the record decl, will mark virtual member functions as
- /// referenced.
- void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD);
+ /// \brief The list of classes whose vtables have been used within
+ /// this translation unit, and the source locations at which the
+ /// first use occurred.
+ llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 16>
+ VTableUses;
+
+ /// \brief The set of classes whose vtables have been used within
+ /// this translation unit, and a bit that will be true if the vtable is
+ /// required to be emitted (otherwise, it should be emitted only if needed
+ /// by code generation).
+ llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed;
+
+ /// \brief A list of all of the dynamic classes in this translation
+ /// unit.
+ llvm::SmallVector<CXXRecordDecl *, 16> DynamicClasses;
+
+ /// \brief Note that the vtable for the given class was used at the
+ /// given location.
+ void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
+ bool DefinitionRequired = false);
/// MarkVirtualMembersReferenced - Will mark all virtual members of the given
/// CXXRecordDecl referenced.
void MarkVirtualMembersReferenced(SourceLocation Loc,
const CXXRecordDecl *RD);
- /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
- /// that might need to have their virtual members marked as referenced.
- /// Returns false if no work was done.
- bool ProcessPendingClassesWithUnmarkedVirtualMembers();
+ /// \brief Define all of the vtables that have been used in this
+ /// translation unit and reference any virtual members used by those
+ /// vtables.
+ ///
+ /// \returns true if any work was done, false otherwise.
+ bool DefineUsedVTables();
void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl);
@@ -2664,6 +2675,8 @@ public:
void BuildBasePathArray(const CXXBasePaths &Paths,
CXXBaseSpecifierArray &BasePath);
+ bool BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath);
+
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
CXXBaseSpecifierArray *BasePath = 0,
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 9f8b344562..1dbdd06eea 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -388,6 +388,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return;
Kind = CastExpr::CK_DerivedToBase;
+
+ // If we are casting to or through a virtual base class, we need a
+ // vtable.
+ if (Self.BasePathInvolvesVirtualBase(BasePath))
+ Self.MarkVTableUsed(OpRange.getBegin(),
+ cast<CXXRecordDecl>(SrcRecord->getDecl()));
return;
}
@@ -398,6 +404,8 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
<< SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
}
+ Self.MarkVTableUsed(OpRange.getBegin(),
+ cast<CXXRecordDecl>(SrcRecord->getDecl()));
// Done. Everything else is run-time checks.
Kind = CastExpr::CK_Dynamic;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b4f5d13d2a..76334e9a12 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4575,12 +4575,14 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
WP.disableCheckFallThrough();
}
- if (!FD->isInvalidDecl())
+ if (!FD->isInvalidDecl()) {
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
-
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
- MaybeMarkVirtualMembersReferenced(Method->getLocation(), Method);
-
+
+ // If this is a constructor, we need a vtable.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
+ MarkVTableUsed(FD->getLocation(), Constructor->getParent());
+ }
+
assert(FD == getCurFunctionDecl() && "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
@@ -5447,37 +5449,6 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD,
"Broken injected-class-name");
}
-// Traverses the class and any nested classes, making a note of any
-// dynamic classes that have no key function so that we can mark all of
-// their virtual member functions as "used" at the end of the translation
-// unit. This ensures that all functions needed by the vtable will get
-// instantiated/synthesized.
-static void
-RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record,
- SourceLocation Loc) {
- // We don't look at dependent or undefined classes.
- if (Record->isDependentContext() || !Record->isDefinition())
- return;
-
- if (Record->isDynamicClass()) {
- const CXXMethodDecl *KeyFunction = S.Context.getKeyFunction(Record);
-
- if (!KeyFunction)
- S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record,
- Loc));
-
- if ((!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined()))
- && Record->getLinkage() == ExternalLinkage)
- S.Diag(Record->getLocation(), diag::warn_weak_vtable) << Record;
- }
- for (DeclContext::decl_iterator D = Record->decls_begin(),
- DEnd = Record->decls_end();
- D != DEnd; ++D) {
- if (CXXRecordDecl *Nested = dyn_cast<CXXRecordDecl>(*D))
- RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc);
- }
-}
-
void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
SourceLocation RBraceLoc) {
AdjustDeclIfTemplate(TagD);
@@ -5489,10 +5460,6 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
// Exit this scope of this tag's definition.
PopDeclContext();
-
- if (isa<CXXRecordDecl>(Tag) && !Tag->getLexicalDeclContext()->isRecord())
- RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag),
- RBraceLoc);
// Notify the consumer that we've defined a tag.
Consumer.HandleTagDeclDefinition(Tag);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 7f8d245158..558746b0fe 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -735,6 +735,18 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
BasePathArray.push_back(Path[I].Base);
}
+/// \brief Determine whether the given base path includes a virtual
+/// base class.
+bool Sema::BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath) {
+ for (CXXBaseSpecifierArray::iterator B = BasePath.begin(),
+ BEnd = BasePath.end();
+ B != BEnd; ++B)
+ if ((*B)->isVirtual())
+ return true;
+
+ return false;
+}
+
/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
/// conversion (where Derived and Base are class types) is
/// well-formed, meaning that the conversion is unambiguous (and
@@ -2466,6 +2478,9 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
}
}
}
+
+ if (Record->isDynamicClass())
+ DynamicClasses.push_back(Record);
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -4154,7 +4169,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
- MaybeMarkVirtualMembersReferenced(CurrentLocation, Constructor);
+ MarkVTableUsed(CurrentLocation, ClassDecl);
}
}
@@ -4183,7 +4198,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
Destructor->setUsed();
- MaybeMarkVirtualMembersReferenced(CurrentLocation, Destructor);
+ MarkVTableUsed(CurrentLocation, ClassDecl);
}
/// \brief Builds a statement that copies the given entity from \p From to
@@ -4641,8 +4656,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
CopyAssignOperator->setBody(Body.takeAs<Stmt>());
-
- MaybeMarkVirtualMembersReferenced(CurrentLocation, CopyAssignOperator);
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
@@ -4670,7 +4683,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
MultiStmtArg(*this, 0, 0),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
- MaybeMarkVirtualMembersReferenced(CurrentLocation, CopyConstructor);
}
CopyConstructor->setUsed();
@@ -6019,90 +6031,120 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
-static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) {
- // Ignore dependent types.
- if (MD->isDependentContext())
- return false;
-
- // Ignore declarations that are not definitions.
- if (!MD->isThisDeclarationADefinition())
- return false;
-
- CXXRecordDecl *RD = MD->getParent();
-
- // Ignore classes without a vtable.
- if (!RD->isDynamicClass())
- return false;
-
- switch (MD->getParent()->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- // Classes that aren't instantiations of templates don't need their
- // virtual methods marked until we see the definition of the key
- // function.
- break;
+void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
+ bool DefinitionRequired) {
+ // Ignore any vtable uses in unevaluated operands or for classes that do
+ // not have a vtable.
+ if (!Class->isDynamicClass() || Class->isDependentContext() ||
+ CurContext->isDependentContext() ||
+ ExprEvalContexts.back().Context == Unevaluated)
+ return;
- case TSK_ImplicitInstantiation:
- // This is a constructor of a class template; mark all of the virtual
- // members as referenced to ensure that they get instantiatied.
- if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
- return true;
- break;
+ // Try to insert this class into the map.
+ Class = cast<CXXRecordDecl>(Class->getCanonicalDecl());
+ std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool>
+ Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired));
+ if (!Pos.second) {
+ Pos.first->second = Pos.first->second || DefinitionRequired;
+ return;
+ }
- case TSK_ExplicitInstantiationDeclaration:
- return false;
+ // Local classes need to have their virtual members marked
+ // immediately. For all other classes, we mark their virtual members
+ // at the end of the translation unit.
+ if (Class->isLocalClass())
+ MarkVirtualMembersReferenced(Loc, Class);
+ else
+ VTableUses.push_back(std::make_pair(Class, Loc));
+}
- case TSK_ExplicitInstantiationDefinition:
- // This is method of a explicit instantiation; mark all of the virtual
- // members as referenced to ensure that they get instantiatied.
- return true;
+bool Sema::DefineUsedVTables() {
+ // If any dynamic classes have their key function defined within
+ // this translation unit, then those vtables are considered "used" and must
+ // be emitted.
+ for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
+ if (const CXXMethodDecl *KeyFunction
+ = Context.getKeyFunction(DynamicClasses[I])) {
+ const FunctionDecl *Definition = 0;
+ if (KeyFunction->getBody(Definition) && !Definition->isInlined() &&
+ !Definition->isImplicit())
+ MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true);
+ }
}
- // Consider only out-of-line definitions of member functions. When we see
- // an inline definition, it's too early to compute the key function.
- if (!MD->isOutOfLine())
+ if (VTableUses.empty())
return false;
+
+ // Note: The VTableUses vector could grow as a result of marking
+ // the members of a class as "used", so we check the size each
+ // time through the loop and prefer indices (with are stable) to
+ // iterators (which are not).
+ for (unsigned I = 0; I != VTableUses.size(); ++I) {
+ CXXRecordDecl *Class
+ = cast_or_null<CXXRecordDecl>(VTableUses[I].first)->getDefinition();
+ if (!Class)
+ continue;
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
-
- // If there is no key function, we will need a copy of the vtable.
- if (!KeyFunction)
- return true;
-
- // If this is the key function, we need to mark virtual members.
- if (KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
- return true;
-
- return false;
-}
-
-void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
- CXXMethodDecl *MD) {
- CXXRecordDecl *RD = MD->getParent();
+ SourceLocation Loc = VTableUses[I].second;
+
+ // If this class has a key function, but that key function is
+ // defined in another translation unit, we don't need to emit the
+ // vtable even though we're using it.
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class);
+ if (KeyFunction && !KeyFunction->getBody()) {
+ switch (KeyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ // The key function is in another translation unit.
+ continue;
- // We will need to mark all of the virtual members as referenced to build the
- // vtable.
- if (!needsVTable(MD, Context))
- return;
+ case TSK_ExplicitInstantiationDefinition:
+ case TSK_ImplicitInstantiation:
+ // We will be instantiating the key function.
+ break;
+ }
+ } else if (!KeyFunction) {
+ // If we have a class with no key function that is the subject
+ // of an explicit instantiation declaration, suppress the
+ // vtable; it will live with the explicit instantiation
+ // definition.
+ bool IsExplicitInstantiationDeclaration
+ = Class->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration;
+ for (TagDecl::redecl_iterator R = Class->redecls_begin(),
+ REnd = Class->redecls_end();
+ R != REnd; ++R) {
+ TemplateSpecializationKind TSK
+ = cast<CXXRecordDecl>(*R)->getTemplateSpecializationKind();
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ IsExplicitInstantiationDeclaration = true;
+ else if (TSK == TSK_ExplicitInstantiationDefinition) {
+ IsExplicitInstantiationDeclaration = false;
+ break;
+ }
+ }
- TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
- if (kind == TSK_ImplicitInstantiation)
- ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc));
- else
- MarkVirtualMembersReferenced(Loc, RD);
-}
+ if (IsExplicitInstantiationDeclaration)
+ continue;
+ }
-bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
- if (ClassesWithUnmarkedVirtualMembers.empty())
- return false;
-
- while (!ClassesWithUnmarkedVirtualMembers.empty()) {
- CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first;
- SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second;
- ClassesWithUnmarkedVirtualMembers.pop_back();
- MarkVirtualMembersReferenced(Loc, RD);
+ // Mark all of the virtual members of this class as referenced, so
+ // that we can build a vtable. Then, tell the AST consumer that a
+ // vtable for this class is required.
+ MarkVirtualMembersReferenced(Loc, Class);
+ CXXRecordDecl *Canonical = cast<CXXRecordDecl>(Class->getCanonicalDecl());
+ Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
+
+ // Optionally warn if we're emitting a weak vtable.
+ if (Class->getLinkage() == ExternalLinkage &&
+ Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
+ if (!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined()))
+ Diag(Class->getLocation(), diag::warn_weak_vtable) << Class;
+ }
}
-
+ VTableUses.clear();
+
return true;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 73493b6066..13f44b9a8a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -7503,17 +7503,19 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
- MaybeMarkVirtualMembersReferenced(Loc, Constructor);
+ MarkVTableUsed(Loc, Constructor->getParent());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
if (Destructor->isImplicit() && !Destructor->isUsed())
DefineImplicitDestructor(Loc, Destructor);
-
+ if (Destructor->isVirtual())
+ MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed())
DefineImplicitCopyAssignment(Loc, MethodDecl);
- }
+ } else if (MethodDecl->isVirtual())
+ MarkVTableUsed(Loc, MethodDecl->getParent());
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// Implicit instantiation of function templates and member functions of
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 8b17f8483d..15c21008be 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -314,8 +314,12 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
// When typeid is applied to an expression other than an lvalue of a
// polymorphic class type [...] [the] expression is an unevaluated
// operand. [...]
- if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
+ if (RecordD->isPolymorphic() && E->isLvalu