]> granicus.if.org Git - clang/commitdiff
Make sure that the key-function computation produces the correct
authorDouglas Gregor <dgregor@apple.com>
Wed, 6 Jan 2010 17:00:51 +0000 (17:00 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 6 Jan 2010 17:00:51 +0000 (17:00 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92839 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDecl.cpp
test/SemaCXX/virtual-member-functions-key-function.cpp

index 383893cc2fc6a9b9c4dfaaef9435345d9da5d856..9ed37f604fce02e888f593df3a14aab42fc78548 100644 (file)
@@ -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);
 }
index 8da6bf559840e553610f1ffe0ed73b25fc97d1d9..2e21fb7365e9e961c6df6bd374fe1ce26d131f2e 100644 (file)
@@ -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() { }