diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index df6f18f95b..87ebea72f2 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2172,11 +2172,11 @@ public: void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor); /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual - /// members might need to be marked as referenced. This is either done when - /// the key function definition is emitted (this is handled by by - /// MaybeMarkVirtualMembersReferenced), or at the end of the translation unit - /// (done by ProcessPendingClassesWithUnmarkedVirtualMembers). - std::map ClassesWithUnmarkedVirtualMembers; + /// 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, 4> + ClassesWithUnmarkedVirtualMembers; /// MaybeMarkVirtualMembersReferenced - If the passed in method is the /// key function of the record decl, will mark virtual member functions as diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0fc61e3b58..383893cc2f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5098,6 +5098,16 @@ 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)); + } + // 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 ecf95d7eb6..623bf8ae7e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2054,7 +2054,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (!Record->isDependentType()) AddImplicitlyDeclaredMembersToClass(Record); - + if (Record->isInvalidDecl()) return; @@ -5693,67 +5693,30 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, if (!RD->isDynamicClass()) return; - if (!MD->isOutOfLine()) { - // The only inline functions we care about are constructors. We also defer - // marking the virtual members as referenced until we've reached the end - // of the translation unit. We do this because we need to know the key - // function of the class in order to determine the key function. - if (isa(MD)) - ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc)); + // Only out-of-line definitions matter. + if (!MD->isOutOfLine()) + return; + + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + if (!KeyFunction || KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) return; - } - switch (RD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: { - const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); - - if (!KeyFunction) { - // This record does not have a key function, so we assume that the vtable - // will be emitted when it's used by the constructor. - if (!isa(MD)) - return; - } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) { - // We don't have the right key function. - return; - } - break; - } - - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - // Always mark the virtual members of an instantiated template. - break; - } - - // Mark the members as referenced. - MarkVirtualMembersReferenced(Loc, RD); - ClassesWithUnmarkedVirtualMembers.erase(RD); + // We will need to mark all of the virtual members as referenced to build the + // vtable. + ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc)); } bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { if (ClassesWithUnmarkedVirtualMembers.empty()) return false; - for (std::map::iterator i = - ClassesWithUnmarkedVirtualMembers.begin(), - e = ClassesWithUnmarkedVirtualMembers.end(); i != e; ++i) { - CXXRecordDecl *RD = i->first; - - const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); - if (KeyFunction) { - // We know that the class has a key function. If the key function was - // declared in this translation unit, then it the class decl would not - // have been in the ClassesWithUnmarkedVirtualMembers map. - continue; - } - - SourceLocation Loc = i->second; + while (!ClassesWithUnmarkedVirtualMembers.empty()) { + CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first; + SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second; + ClassesWithUnmarkedVirtualMembers.pop_back(); MarkVirtualMembersReferenced(Loc, RD); } - ClassesWithUnmarkedVirtualMembers.clear(); return true; } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index d974f89bc6..2db0deb509 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1060,6 +1060,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Exit the scope of this instantiation. CurContext = PreviousContext; + // 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 (Instantiation->isDynamicClass() && !Context.getKeyFunction(Instantiation)) + ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation, + PointOfInstantiation)); + if (!Invalid) Consumer.HandleTagDeclDefinition(Instantiation); diff --git a/test/SemaCXX/implicit-virtual-member-functions.cpp b/test/SemaCXX/implicit-virtual-member-functions.cpp index a6b1f8c537..4ae9eae3b3 100644 --- a/test/SemaCXX/implicit-virtual-member-functions.cpp +++ b/test/SemaCXX/implicit-virtual-member-functions.cpp @@ -15,15 +15,15 @@ void B::f() { // expected-note {{implicit default destructor for 'struct B' firs struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}} C(); void operator delete(void *, int); // expected-note {{'operator delete' declared here}} -}; +}; // expected-note {{implicit default destructor for 'struct C' first required here}} -C::C() { } // expected-note {{implicit default destructor for 'struct C' first required here}} +C::C() { } struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}} void operator delete(void *, int); // expected-note {{'operator delete' declared here}} -}; +}; // expected-note {{implicit default destructor for 'struct D' first required here}} void f() { - new D; // expected-note {{implicit default destructor for 'struct D' first required here}} + new D; } diff --git a/test/SemaCXX/virtual-member-functions-key-function.cpp b/test/SemaCXX/virtual-member-functions-key-function.cpp index 3d048595e9..8da6bf5598 100644 --- a/test/SemaCXX/virtual-member-functions-key-function.cpp +++ b/test/SemaCXX/virtual-member-functions-key-function.cpp @@ -4,19 +4,15 @@ struct A { }; struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}} - B() { } // expected-note {{implicit default destructor for 'struct B' first required here}} + B() { } void operator delete(void *, int); // expected-note {{'operator delete' declared here}} -}; +}; // expected-note {{implicit default destructor for 'struct B' first required here}} struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}} void operator delete(void *, int); // expected-note {{'operator delete' declared here}} -}; +}; // expected-note {{implicit default destructor for 'struct C' first required here}} void f() { - // new B should mark the constructor as used, which then marks - // all the virtual members as used, because B has no key function. (void)new B; - - // Same here, except that C has an implicit constructor. - (void)new C; // expected-note {{implicit default destructor for 'struct C' first required here}} + (void)new C; } diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp index 69ae0807b4..a9eb729ed5 100644 --- a/test/SemaTemplate/virtual-member-functions.cpp +++ b/test/SemaTemplate/virtual-member-functions.cpp @@ -3,14 +3,19 @@ namespace PR5557 { template struct A { A(); + virtual void anchor(); // expected-note{{instantiation}} virtual int a(T x); }; template A::A() {} +template void A::anchor() { } + template int A::a(T x) { return *x; // expected-error{{requires pointer operand}} } -A x; // expected-note{{instantiation}} +void f(A x) { + x.anchor(); +} template struct X { @@ -20,3 +25,19 @@ struct X { template<> void X::f() { } } + +template +struct Base { + virtual ~Base() { + int *ptr = 0; + T t = ptr; // expected-error{{cannot initialize}} + } +}; + +template +struct Derived : Base { + virtual void foo() { } +}; + +template struct Derived; // expected-note{{instantiation}} +