From: Anders Carlsson Date: Thu, 11 Feb 2010 18:20:28 +0000 (+0000) Subject: More vtable layout dumper improvements. Handle destructors, dump the complete functio... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=848fa64143fbe5ae62a601ad61277f741e54dfab;p=clang More vtable layout dumper improvements. Handle destructors, dump the complete function type of the member functions (using PredefinedExpr::ComputeName. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95887 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 4a8b0dbc62..114a19800f 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -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); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 1af4bf8773..73f6a2c915 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -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(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(FD)) { - if (MD->isVirtual()) + if (MD->isVirtual() && IT != PrettyFunctionNoVirtual) Out << "virtual "; if (MD->isStatic()) Out << "static "; diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index bb74f9b2f5..ad4fd63cbf 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -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()); diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index d2b6c08712..93e2cb7fc6 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -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(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(MD)); } + static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { + return VtableComponent(CK_CompleteDtorPointer, + reinterpret_cast(DD)); + } + + static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { + return VtableComponent(CK_DeletingDtorPointer, + reinterpret_cast(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(getPointer()); } - + + const CXXDestructorDecl *getDestructorDecl() const { + assert((getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); + + return reinterpret_cast(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(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(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; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 22856433f3..3ce3c28058 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1653,8 +1653,7 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, if (cast(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(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 0dd7990f50..2d354575f0 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -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(); diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp index beb82ef905..dd9109e158 100644 --- a/test/CodeGenCXX/vtable-layout.cpp +++ b/test/CodeGenCXX/vtable-layout.cpp @@ -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() { } + +}