]> granicus.if.org Git - clang/commitdiff
MS ABI: Let non-virtual method overloads participate in vftable ordering
authorReid Kleckner <reid@kleckner.net>
Wed, 19 Feb 2014 22:06:10 +0000 (22:06 +0000)
committerReid Kleckner <reid@kleckner.net>
Wed, 19 Feb 2014 22:06:10 +0000 (22:06 +0000)
In the Microsoft ABI, the vftable is laid out as if all methods in every
overload set were declared in reverse order of declaration at the point
of declaration of the first overload in the set.

Previously we only considered virtual methods in an overload set, but
MSVC includes non-virtual methods for ordering purposes.

Fixes PR18902.

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

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

index 30f95d0f25b538b12df68d287f98ec84675e9c5e..e0e30a122a880c193b12847e8428a85296f48a6a 100644 (file)
@@ -2789,7 +2789,7 @@ static void GroupNewVirtualOverloads(
   // Put the virtual methods into VirtualMethods in the proper order:
   // 1) Group overloads by declaration name. New groups are added to the
   //    vftable in the order of their first declarations in this class
-  //    (including overrides).
+  //    (including overrides and non-virtual methods).
   // 2) In each group, new overloads appear in the reverse order of declaration.
   typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup;
   SmallVector<MethodGroup, 10> Groups;
@@ -2798,16 +2798,14 @@ static void GroupNewVirtualOverloads(
   for (CXXRecordDecl::method_iterator I = RD->method_begin(),
        E = RD->method_end(); I != E; ++I) {
     const CXXMethodDecl *MD = *I;
-    if (!MD->isVirtual())
-      continue;
 
     VisitedGroupIndicesTy::iterator J;
     bool Inserted;
     llvm::tie(J, Inserted) = VisitedGroupIndices.insert(
         std::make_pair(MD->getDeclName(), Groups.size()));
     if (Inserted)
-      Groups.push_back(MethodGroup(1, MD));
-    else
+      Groups.push_back(MethodGroup());
+    if (I->isVirtual())
       Groups[J->second].push_back(MD);
   }
 
index 428d9ee7da04a6a0fcf59a5e5f9a555501eb8c80..088ed17ee6849c6daa66dce3a931b587b8dec063 100644 (file)
@@ -15,6 +15,8 @@
 // RUN: FileCheck --check-prefix=CHECK-M %s < %t
 // RUN: FileCheck --check-prefix=CHECK-N %s < %t
 // RUN: FileCheck --check-prefix=CHECK-O %s < %t
+// RUN: FileCheck --check-prefix=CHECK-Q %s < %t
+// RUN: FileCheck --check-prefix=CHECK-R %s < %t
 
 struct A {
   // CHECK-A: VFTable for 'A' (3 entries)
@@ -260,3 +262,28 @@ P p;
 
 // CHECK-O: VFTable for 'O' (1 entries)
 // CHECK-O-NEXT: 0 | A *O::f()
+
+struct Q {
+  // CHECK-Q: VFTable for 'Q' (2 entries)
+  // CHECK-Q-NEXT: 0 | void Q::foo(int)
+  // CHECK-Q-NEXT: 1 | void Q::bar(int)
+  void foo(short);
+  void bar(short);
+  virtual void bar(int);
+  virtual void foo(int);
+};
+
+Q q;
+
+// Inherited non-virtual overloads don't participate in the ordering.
+struct R : Q {
+  // CHECK-R: VFTable for 'Q' in 'R' (4 entries)
+  // CHECK-R-NEXT: 0 | void Q::foo(int)
+  // CHECK-R-NEXT: 1 | void Q::bar(int)
+  // CHECK-R-NEXT: 2 | void R::bar(long)
+  // CHECK-R-NEXT: 3 | void R::foo(long)
+  virtual void bar(long);
+  virtual void foo(long);
+};
+
+R r;