diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 383893cc2f..9ed37f604f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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(*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(Tag)) { - if (!Record->isDependentContext() && Record->isDynamicClass() && - !Context.getKeyFunction(Record)) - ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, - RBraceLoc)); - } - + if (isa(Tag) && !Tag->getDeclContext()->isRecord()) + RecordDynamicClassesWithNoKeyFunction(*this, cast(Tag), + RBraceLoc); + // Notify the consumer that we've defined a tag. Consumer.HandleTagDeclDefinition(Tag); } diff --git a/test/SemaCXX/virtual-member-functions-key-function.cpp b/test/SemaCXX/virtual-member-functions-key-function.cpp index 8da6bf5598..2e21fb7365 100644 --- a/test/SemaCXX/virtual-member-functions-key-function.cpp +++ b/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() { }