forked from OSchip/llvm-project
More vtable layout dumper improvements. Handle destructors, dump the complete function type of the member functions (using PredefinedExpr::ComputeName.
llvm-svn: 95887
This commit is contained in:
parent
69837bed2f
commit
5bd8d19291
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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 ";
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() { }
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue