summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-01-06 17:00:51 +0000
committerDouglas Gregor <dgregor@apple.com>2010-01-06 17:00:51 +0000
commit859f0ae041a41d484a1b6ce75ee813633d88ab36 (patch)
tree4e551ac1ab9b04ddbf7e842f69fdbf2828219cde
parent127286c58ba78e15bd8f79b7ba50dfb2a71f41b9 (diff)
downloadbcm5719-llvm-859f0ae041a41d484a1b6ce75ee813633d88ab36.tar.gz
bcm5719-llvm-859f0ae041a41d484a1b6ce75ee813633d88ab36.zip
Make sure that the key-function computation produces the correct
result for a nested class whose first non-pure virtual member function has an inline body. Previously, we were checking for the key function before we had seen the (delayed) inline body. llvm-svn: 92839
-rw-r--r--clang/lib/Sema/SemaDecl.cpp37
-rw-r--r--clang/test/SemaCXX/virtual-member-functions-key-function.cpp11
2 files changed, 38 insertions, 10 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 383893cc2fc..9ed37f604fc 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5086,6 +5086,29 @@ 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() && !S.Context.getKeyFunction(Record))
+ S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, Loc));
+
+ 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);
@@ -5098,16 +5121,10 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
// Exit this scope of this tag's definition.
PopDeclContext();
- // If this is a polymorphic C++ class without a key function, we'll
- // have to mark all of the virtual members to allow emission of a vtable
- // in this translation unit.
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) {
- if (!Record->isDependentContext() && Record->isDynamicClass() &&
- !Context.getKeyFunction(Record))
- ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record,
- RBraceLoc));
- }
-
+ if (isa<CXXRecordDecl>(Tag) && !Tag->getDeclContext()->isRecord())
+ RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag),
+ RBraceLoc);
+
// Notify the consumer that we've defined a tag.
Consumer.HandleTagDeclDefinition(Tag);
}
diff --git a/clang/test/SemaCXX/virtual-member-functions-key-function.cpp b/clang/test/SemaCXX/virtual-member-functions-key-function.cpp
index 8da6bf55984..2e21fb7365e 100644
--- a/clang/test/SemaCXX/virtual-member-functions-key-function.cpp
+++ b/clang/test/SemaCXX/virtual-member-functions-key-function.cpp
@@ -16,3 +16,14 @@ void f() {
(void)new B;
(void)new C;
}
+
+// Make sure that the key-function computation is consistent when the
+// first virtual member function of a nested class has an inline body.
+struct Outer {
+ struct Inner {
+ virtual void f() { }
+ void g();
+ };
+};
+
+void Outer::Inner::g() { }
OpenPOWER on IntegriCloud