]> granicus.if.org Git - clang/commitdiff
Make our marking of virtual members functions in a class be
authorDouglas Gregor <dgregor@apple.com>
Wed, 6 Jan 2010 04:44:19 +0000 (04:44 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 6 Jan 2010 04:44:19 +0000 (04:44 +0000)
deterministic and work properly with templates. Once a class that
needs a vtable has been defined, we now do one if two things:

  - If the class has no key function, we place the class on a list of
    classes whose virtual functions will need to be "marked" at the
    end of the translation unit. The delay until the end of the
    translation unit is needed because we might see template
    specializations of these virtual functions.
  - If the class has a key function, we do nothing; when the key
    function is defined, the class will be placed on the
    aforementioned list.

At the end of the translation unit, we "mark" all of the virtual
functions of the classes on the list as used, possibly causing
template instantiation and other classes to be added to the
list. This gets LLVM's lib/Support/CommandLine.cpp compiling again.

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

lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/SemaCXX/implicit-virtual-member-functions.cpp
test/SemaCXX/virtual-member-functions-key-function.cpp
test/SemaTemplate/virtual-member-functions.cpp

index df6f18f95b57b20779a25a28a6d02c023f7f0f78..87ebea72f216a8eaeffc9d330c7bf7a24f3d5d72 100644 (file)
@@ -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 
index 0fc61e3b5877223f7ceb056b5b859345c96fff53..383893cc2fc6a9b9c4dfaaef9435345d9da5d856 100644 (file)
@@ -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);
 }
index ecf95d7eb662c6fbe29b61c0fe704027dfd8e48a..623bf8ae7e39b58da2f5b2fbcad13202f2c72369 100644 (file)
@@ -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;
 }
 
index d974f89bc6095517e73483ff48ab43dda7343033..2db0deb5098b63f7e09f874a379d916bff2409d2 100644 (file)
@@ -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);
 
index a6b1f8c537d2bc95925fc3b44f88a2cce42d2b4c..4ae9eae3b316d505588018f61e332b7370c1e861 100644 (file)
@@ -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; 
 }
 
index 3d048595e94e0f2e446bb209231a190e1a0ee133..8da6bf559840e553610f1ffe0ed73b25fc97d1d9 100644 (file)
@@ -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;
 }
index 69ae0807b4c5b510edd08d0b8329d134b7a406ed..a9eb729ed5a1624348125671ca613b3a0f3d2c8c 100644 (file)
@@ -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}}
+