[PATCH] Fix PR17382 - properly group virtual method overloads in the vftable

Timur Iskhodzhanov timurrrr at google.com
Fri Oct 4 10:16:03 PDT 2013


  Fix an include (I've used a StringSet in an intermediate version, forgot to update)

Hi rnk,

http://llvm-reviews.chandlerc.com/D1839

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D1839?vs=4678&id=4679#toc

Files:
  lib/AST/VTableBuilder.cpp
  test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp

Index: lib/AST/VTableBuilder.cpp
===================================================================
--- lib/AST/VTableBuilder.cpp
+++ lib/AST/VTableBuilder.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
@@ -2766,20 +2767,54 @@
       llvm_unreachable("Found a duplicate primary base!");
   }
 
+  // Put the virtual methods in the proper order.
+  // 1) Group overloads by name. New groups are added to the
+  //    vftable in the order of their first declarations in this class
+  //    (including overrides).
+  // 2) In each group, new overloads appear in the reverse order of declaration.
+  SmallVector<const CXXMethodDecl*, 10> VirtualMethods;
+  {
+    typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup;
+    SmallVector<MethodGroup, 10> Groups;
+    llvm::StringMap<unsigned> VisitedGroupIndices;
+    for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+         E = RD->method_end(); I != E; ++I) {
+      const CXXMethodDecl *MD = *I;
+      if (!MD->isVirtual())
+        continue;
+
+      if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+        Groups.push_back(MethodGroup(1, DD));
+        continue;
+      }
+
+      StringRef MyName = MD->getName();
+      unsigned GroupIdx =
+          VisitedGroupIndices.GetOrCreateValue(MyName, Groups.size())
+              .getValue();
+      if (GroupIdx == Groups.size()) {
+        Groups.push_back(MethodGroup(1, MD));
+      } else {
+        Groups[GroupIdx].push_back(MD);
+      }
+    }
+
+    for (unsigned I = 0, E = Groups.size(); I != E; ++I) {
+      const MethodGroup &G = Groups[I];
+      VirtualMethods.append(G.rbegin(), G.rend());
+    }
+  }
+
   // Now go through all virtual member functions and add them to the current
   // vftable. This is done by
   //  - replacing overridden methods in their existing slots, as long as they
   //    don't require return adjustment; calculating This adjustment if needed.
   //  - adding new slots for methods of the current base not present in any
   //    sub-bases;
   //  - adding new slots for methods that require Return adjustment.
   // We keep track of the methods visited in the sub-bases in MethodInfoMap.
-  for (CXXRecordDecl::method_iterator I = RD->method_begin(),
-       E = RD->method_end(); I != E; ++I) {
-    const CXXMethodDecl *MD = *I;
-
-    if (!MD->isVirtual())
-      continue;
+  for (unsigned I = 0, E = VirtualMethods.size(); I != E; ++I) {
+    const CXXMethodDecl *MD = VirtualMethods[I];
 
     FinalOverriders::OverriderInfo Overrider =
         Overriders.getOverrider(MD, Base.getBaseOffset());
Index: test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
+++ test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
@@ -9,6 +9,10 @@
 // RUN: FileCheck --check-prefix=CHECK-F %s < %t
 // RUN: FileCheck --check-prefix=CHECK-G %s < %t
 // RUN: FileCheck --check-prefix=CHECK-I %s < %t
+// RUN: FileCheck --check-prefix=CHECK-J %s < %t
+// RUN: FileCheck --check-prefix=CHECK-K %s < %t
+// RUN: FileCheck --check-prefix=CHECK-L %s < %t
+// RUN: FileCheck --check-prefix=CHECK-M %s < %t
 
 struct A {
   // CHECK-A: VFTable for 'A' (3 entries)
@@ -149,3 +153,85 @@
 };
 
 I i;
+
+struct J {
+  // CHECK-J: VFTable for 'J' (6 entries)
+  // CHECK-J-NEXT: 0 | void J::foo(long)
+  // CHECK-J-NEXT: 1 | void J::foo(int)
+  // CHECK-J-NEXT: 2 | void J::foo(short)
+  // CHECK-J-NEXT: 3 | void J::bar(long)
+  // CHECK-J-NEXT: 4 | void J::bar(int)
+  // CHECK-J-NEXT: 5 | void J::bar(short)
+  virtual void foo(short);
+  virtual void bar(short);
+  virtual void foo(int);
+  virtual void bar(int);
+  virtual void foo(long);
+  virtual void bar(long);
+};
+
+J j;
+
+struct K : J {
+  // CHECK-K: VFTable for 'J' in 'K' (9 entries)
+  // CHECK-K-NEXT: 0 | void J::foo(long)
+  // CHECK-K-NEXT: 1 | void J::foo(int)
+  // CHECK-K-NEXT: 2 | void J::foo(short)
+  // CHECK-K-NEXT: 3 | void J::bar(long)
+  // CHECK-K-NEXT: 4 | void J::bar(int)
+  // CHECK-K-NEXT: 5 | void J::bar(short)
+  // CHECK-K-NEXT: 6 | void K::bar(double)
+  // CHECK-K-NEXT: 7 | void K::bar(float)
+  // CHECK-K-NEXT: 8 | void K::foo(float)
+  virtual void bar(float);
+  virtual void foo(float);
+  virtual void bar(double);
+};
+
+K k;
+
+struct L : J {
+  // CHECK-L: VFTable for 'J' in 'L' (9 entries)
+  // CHECK-L-NEXT: 0 | void J::foo(long)
+  // CHECK-L-NEXT: 1 | void L::foo(int)
+  // CHECK-L-NEXT: 2 | void J::foo(short)
+  // CHECK-L-NEXT: 3 | void J::bar(long)
+  // CHECK-L-NEXT: 4 | void J::bar(int)
+  // CHECK-L-NEXT: 5 | void J::bar(short)
+  // CHECK-L-NEXT: 6 | void L::foo(float)
+  // CHECK-L-NEXT: 7 | void L::bar(double)
+  // CHECK-L-NEXT: 8 | void L::bar(float)
+
+  // Since the J::foo(int) override is the first method in  the class,
+  // foo(float) precedes the bar(double) and bar(float) in the vftable.
+  virtual void foo(int);
+  virtual void bar(float);
+  virtual void foo(float);
+  virtual void bar(double);
+};
+
+L l;
+
+struct M : J {
+  // CHECK-M: VFTable for 'J' in 'M' (11 entries)
+  // CHECK-M-NEXT:  0 | void J::foo(long)
+  // CHECK-M-NEXT:  1 | void M::foo(int)
+  // CHECK-M-NEXT:  2 | void J::foo(short)
+  // CHECK-M-NEXT:  3 | void J::bar(long)
+  // CHECK-M-NEXT:  4 | void J::bar(int)
+  // CHECK-M-NEXT:  5 | void J::bar(short)
+  // CHECK-M-NEXT:  6 | void M::foo(float)
+  // CHECK-M-NEXT:  7 | void M::spam(long)
+  // CHECK-M-NEXT:  8 | void M::spam(int)
+  // CHECK-M-NEXT:  9 | void M::bar(double)
+  // CHECK-M-NEXT: 10 | void M::bar(float)
+
+  virtual void foo(int);
+  virtual void spam(int);
+  virtual void bar(float);
+  virtual void bar(double);
+  virtual void foo(float);
+  virtual void spam(long);
+};
+
+M m;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1839.2.patch
Type: text/x-patch
Size: 6007 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131004/10f13bde/attachment.bin>


More information about the cfe-commits mailing list