]> granicus.if.org Git - clang/commitdiff
More vtable layout dumper improvements. Handle destructors, dump the complete functio...
authorAnders Carlsson <andersca@mac.com>
Thu, 11 Feb 2010 18:20:28 +0000 (18:20 +0000)
committerAnders Carlsson <andersca@mac.com>
Thu, 11 Feb 2010 18:20:28 +0000 (18:20 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95887 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
lib/AST/Expr.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGVtable.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/CodeGenCXX/vtable-layout.cpp

index 4a8b0dbc62c7e32b5e3337076db35798ef0e0cf5..114a19800f50f89be0c981b9746c4a883b04fe61 100644 (file)
@@ -568,7 +568,10 @@ public:
   enum IdentType {
     Func,
     Function,
-    PrettyFunction
+    PrettyFunction,
+    /// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
+    /// 'virtual' keyword is omitted for virtual member functions.
+    PrettyFunctionNoVirtual
   };
 
 private:
@@ -589,8 +592,7 @@ public:
   SourceLocation getLocation() const { return Loc; }
   void setLocation(SourceLocation L) { Loc = L; }
 
-  static std::string ComputeName(ASTContext &Context, IdentType IT,
-                                 const Decl *CurrentDecl);
+  static std::string ComputeName(IdentType IT, const Decl *CurrentDecl);
 
   virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
 
index 1af4bf87732c7cc2dff291e4808da5c8a5c42494..73f6a2c9156e97df9eea6a58444aed5b97508e32 100644 (file)
@@ -163,17 +163,18 @@ SourceRange DeclRefExpr::getSourceRange() const {
 
 // FIXME: Maybe this should use DeclPrinter with a special "print predefined
 // expr" policy instead.
-std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT,
-                                        const Decl *CurrentDecl) {
+std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
+  ASTContext &Context = CurrentDecl->getASTContext();
+
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
-    if (IT != PrettyFunction)
+    if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
       return FD->getNameAsString();
 
     llvm::SmallString<256> Name;
     llvm::raw_svector_ostream Out(Name);
 
     if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
-      if (MD->isVirtual())
+      if (MD->isVirtual() && IT != PrettyFunctionNoVirtual)
         Out << "virtual ";
       if (MD->isStatic())
         Out << "static ";
index bb74f9b2f555071df9d4f639ea81495204a24196..ad4fd63cbf6299751b37311bd0418dda4d44ba68 100644 (file)
@@ -1185,8 +1185,7 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) {
   GlobalVarName += FnName;
 
   std::string FunctionName =
-    PredefinedExpr::ComputeName(getContext(), (PredefinedExpr::IdentType)Type,
-                                CurCodeDecl);
+    PredefinedExpr::ComputeName((PredefinedExpr::IdentType)Type, CurCodeDecl);
 
   llvm::Constant *C =
     CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str());
index d2b6c08712ed2db5f5eeb9fe2414b379fd77f9df..93e2cb7fc6a436d0817267a7a0fa8468c1ae7a47 100644 (file)
@@ -32,7 +32,13 @@ public:
     CK_VBaseOffset,
     CK_OffsetToTop,
     CK_RTTI,
-    CK_VFunctionPointer
+    CK_FunctionPointer,
+    
+    /// CK_CompleteDtorPointer - A pointer to the complete destructor.
+    CK_CompleteDtorPointer,
+    
+    /// CK_DeletingDtorPointer - A pointer to the deleting destructor.
+    CK_DeletingDtorPointer
   };
 
   /// dump - Dump the contents of this component to the given stream.
@@ -48,12 +54,22 @@ public:
 
   static VtableComponent MakeFunction(const CXXMethodDecl *MD) {
     assert(!isa<CXXDestructorDecl>(MD) && 
-           "Don't know how to handle dtors yet!");
+           "Don't use MakeFunction with destructors!");
 
-    return VtableComponent(CK_VFunctionPointer, 
+    return VtableComponent(CK_FunctionPointer, 
                            reinterpret_cast<uintptr_t>(MD));
   }
   
+  static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
+    return VtableComponent(CK_CompleteDtorPointer,
+                           reinterpret_cast<uintptr_t>(DD));
+  }
+
+  static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
+    return VtableComponent(CK_DeletingDtorPointer, 
+                           reinterpret_cast<uintptr_t>(DD));
+  }
+
   /// getKind - Get the kind of this vtable component.
   Kind getKind() const {
     return (Kind)(Value & 0x7);
@@ -72,11 +88,18 @@ public:
   }
   
   const CXXMethodDecl *getFunctionDecl() const {
-    assert(getKind() == CK_VFunctionPointer);
+    assert(getKind() == CK_FunctionPointer);
     
     return reinterpret_cast<CXXMethodDecl *>(getPointer());
   }
-  
+
+  const CXXDestructorDecl *getDestructorDecl() const {
+    assert((getKind() == CK_CompleteDtorPointer ||
+            getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
+    
+    return reinterpret_cast<CXXDestructorDecl *>(getPointer());
+  }
+
 private:
   VtableComponent(Kind ComponentKind, int64_t Offset) {
     assert((ComponentKind == CK_VCallOffset || 
@@ -89,7 +112,9 @@ private:
 
   VtableComponent(Kind ComponentKind, uintptr_t Ptr) {
     assert((ComponentKind == CK_RTTI || 
-            ComponentKind == CK_VFunctionPointer) &&
+            ComponentKind == CK_FunctionPointer ||
+            ComponentKind == CK_CompleteDtorPointer ||
+            ComponentKind == CK_DeletingDtorPointer) &&
             "Invalid component kind!");
     
     assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
@@ -105,9 +130,11 @@ private:
   }
 
   uintptr_t getPointer() const {
-    assert((getKind() == CK_RTTI || getKind() == CK_VFunctionPointer) &&
+    assert((getKind() == CK_RTTI || 
+            getKind() == CK_FunctionPointer ||
+            getKind() == CK_CompleteDtorPointer ||
+            getKind() == CK_DeletingDtorPointer) &&
            "Invalid component kind!");
-  
     
     return static_cast<uintptr_t>(Value & ~7ULL);
   }
@@ -173,8 +200,14 @@ void VtableBuilder::layoutSimpleVtable(const CXXRecordDecl *RD) {
     if (!MD->isVirtual())
       continue;
     
-    // Add the function.
-    Components.push_back(VtableComponent::MakeFunction(MD));
+    if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+      // Add both the complete destructor and the deleting destructor.
+      Components.push_back(VtableComponent::MakeCompleteDtor(DD));
+      Components.push_back(VtableComponent::MakeDeletingDtor(DD));
+    } else {
+      // Add the function.
+      Components.push_back(VtableComponent::MakeFunction(MD));
+    }
   }
 }
 
@@ -229,11 +262,27 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
       Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
       break;
     
-    case VtableComponent::CK_VFunctionPointer: {
+    case VtableComponent::CK_FunctionPointer: {
       const CXXMethodDecl *MD = Component.getFunctionDecl();
 
-      Out << MD->getQualifiedNameAsString();
+      std::string Str = 
+        PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, 
+                                    MD);
+      Out << Str;
+      break;
+    }
 
+    case VtableComponent::CK_CompleteDtorPointer: {
+      const CXXDestructorDecl *DD = Component.getDestructorDecl();
+      
+      Out << DD->getQualifiedNameAsString() << "() [complete]";
+      break;
+    }
+
+    case VtableComponent::CK_DeletingDtorPointer: {
+      const CXXDestructorDecl *DD = Component.getDestructorDecl();
+      
+      Out << DD->getQualifiedNameAsString() << "() [deleting]";
       break;
     }
 
index 22856433f30f1ff9780f0e7020915d83c9798e7a..3ce3c28058538bdf8c54a3027059ed644703a30e 100644 (file)
@@ -1653,8 +1653,7 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
   if (cast<DeclContext>(currentDecl)->isDependentContext()) {
     ResTy = Context.DependentTy;
   } else {
-    unsigned Length =
-      PredefinedExpr::ComputeName(Context, IT, currentDecl).length();
+    unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
 
     llvm::APInt LengthI(32, Length + 1);
     ResTy = Context.CharTy.withConst();
index 0dd7990f504ee7a6985791165d5b57587fdf2ba6..2d354575f0e4fd6cd9c5c1eeeca67c61ea875fc9 100644 (file)
@@ -687,8 +687,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
 
   PredefinedExpr::IdentType IT = E->getIdentType();
 
-  unsigned Length =
-    PredefinedExpr::ComputeName(getSema().Context, IT, currentDecl).length();
+  unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
 
   llvm::APInt LengthI(32, Length + 1);
   QualType ResTy = getSema().Context.CharTy.withConst();
index beb82ef90548f87e102148baf15e67ece9fdc9e0..dd9109e15894a9925e41a540e512a12143d52cdc 100644 (file)
@@ -5,12 +5,36 @@ namespace Test1 {
 // CHECK-NEXT:   0 | offset_to_top (0)
 // CHECK-NEXT:   1 | Test1::A RTTI
 // CHECK-NEXT:       -- (Test1::A, 0) vtable address --
-// CHECK-NEXT:   2 | Test1::A::f
+// CHECK-NEXT:   2 | void Test1::A::f()
 struct A {
   virtual void f();
 };
 
 void A::f() { }
-
 }
 
+namespace Test2 {
+
+// This is a smoke test of the vtable dumper.
+// CHECK:      Vtable for 'Test2::A' (8 entries).
+// CHECK-NEXT:   0 | offset_to_top (0)
+// CHECK-NEXT:   1 | Test2::A RTTI
+// CHECK-NEXT:       -- (Test2::A, 0) vtable address --
+// CHECK-NEXT:   2 | void Test2::A::f()
+// CHECK-NEXT:   3 | void Test2::A::f() const
+// CHECK-NEXT:   4 | Test2::A *Test2::A::g(int)
+// CHECK-NEXT:   5 | Test2::A::~A() [complete]
+// CHECK-NEXT:   6 | Test2::A::~A() [deleting]
+// CHECK-NEXT:   7 | void Test2::A::h()
+struct A {
+  virtual void f();
+  virtual void f() const;
+  
+  virtual A* g(int a);
+  virtual ~A();
+  virtual void h();
+};
+
+void A::f() { }
+
+}