aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/Sema.h10
-rw-r--r--lib/Sema/SemaDecl.cpp10
-rw-r--r--lib/Sema/SemaDeclCXX.cpp65
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp7
-rw-r--r--test/SemaCXX/implicit-virtual-member-functions.cpp8
-rw-r--r--test/SemaCXX/virtual-member-functions-key-function.cpp12
-rw-r--r--test/SemaTemplate/virtual-member-functions.cpp23
7 files changed, 66 insertions, 69 deletions
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<CXXRecordDecl *, SourceLocation> 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<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
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<CXXRecordDecl>(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<CXXConstructorDecl>(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<CXXConstructorDecl>(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<CXXRecordDecl *, SourceLocation>::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 <class T> struct A {
A();
+ virtual void anchor(); // expected-note{{instantiation}}
virtual int a(T x);
};
template<class T> A<T>::A() {}
+template<class T> void A<T>::anchor() { }
+
template<class T> int A<T>::a(T x) {
return *x; // expected-error{{requires pointer operand}}
}
-A<int> x; // expected-note{{instantiation}}
+void f(A<int> x) {
+ x.anchor();
+}
template<typename T>
struct X {
@@ -20,3 +25,19 @@ struct X {
template<>
void X<int>::f() { }
}
+
+template<typename T>
+struct Base {
+ virtual ~Base() {
+ int *ptr = 0;
+ T t = ptr; // expected-error{{cannot initialize}}
+ }
+};
+
+template<typename T>
+struct Derived : Base<T> {
+ virtual void foo() { }
+};
+
+template struct Derived<int>; // expected-note{{instantiation}}
+