27 #include "TClingUtils.h"
31 #include "cling/Interpreter/Interpreter.h"
32 #include "cling/Interpreter/Transaction.h"
35 #include "clang/AST/ASTContext.h"
36 #include "clang/AST/Decl.h"
37 #include "clang/AST/DeclCXX.h"
38 #include "clang/AST/PrettyPrinter.h"
39 #include "clang/AST/RecordLayout.h"
40 #include "clang/AST/Type.h"
41 #include "clang/AST/CXXInheritance.h"
44 #include "llvm/Support/Casting.h"
45 #include "llvm/Support/raw_ostream.h"
46 #include "llvm/ExecutionEngine/ExecutionEngine.h"
47 #include "llvm/IR/Module.h"
54 using namespace clang;
57 TClingBaseClassInfo::TClingBaseClassInfo(cling::Interpreter* interp,
59 : fInterp(interp), fClassInfo(0), fFirstTime(true), fDescend(false),
60 fDecl(0), fIter(0), fBaseInfo(0), fOffset(0L), fClassInfoOwnership(true)
65 fClassInfo =
new TClingClassInfo(interp);
68 fClassInfo =
new TClingClassInfo(*ci);
69 if (!fClassInfo->GetDecl()) {
72 const clang::CXXRecordDecl* CRD =
73 llvm::dyn_cast<clang::CXXRecordDecl>(fClassInfo->GetDecl());
82 cling::Interpreter::PushTransactionRAII RAII(fInterp);
83 fIter = CRD->bases_begin();
87 TClingBaseClassInfo::TClingBaseClassInfo(cling::Interpreter* interp,
88 TClingClassInfo* derived,
89 TClingClassInfo* base)
90 : fInterp(interp), fClassInfo(0), fFirstTime(true), fDescend(false),
91 fDecl(0), fIter(0), fBaseInfo(0), fOffset(0L), fClassInfoOwnership(false)
95 if (!derived->GetDecl()) {
98 const clang::CXXRecordDecl* CRD =
99 llvm::dyn_cast<clang::CXXRecordDecl>(derived->GetDecl());
100 const clang::CXXRecordDecl* BaseCRD =
101 llvm::dyn_cast<clang::CXXRecordDecl>(base->GetDecl());
102 if (!CRD || !BaseCRD) {
108 fClassInfo = derived;
112 clang::CXXBasePaths Paths;
115 cling::Interpreter::PushTransactionRAII RAII(fInterp);
117 if (!CRD->isDerivedFrom(BaseCRD, Paths)) {
122 fBaseInfo =
new TClingClassInfo(*base);
123 fIter = CRD->bases_end();
126 TClingBaseClassInfo::TClingBaseClassInfo(
const TClingBaseClassInfo& rhs)
127 : fInterp(rhs.fInterp), fClassInfo(0), fFirstTime(rhs.fFirstTime),
128 fDescend(rhs.fDescend), fDecl(rhs.fDecl), fIter(rhs.fIter), fBaseInfo(0),
129 fIterStack(rhs.fIterStack), fOffset(rhs.fOffset), fClassInfoOwnership(true)
132 fClassInfo =
new TClingClassInfo(*rhs.fClassInfo);
133 fBaseInfo =
new TClingClassInfo(*rhs.fBaseInfo);
136 TClingBaseClassInfo& TClingBaseClassInfo::operator=(
137 const TClingBaseClassInfo& rhs)
140 fInterp = rhs.fInterp;
141 if (fClassInfoOwnership)
143 fClassInfo =
new TClingClassInfo(*rhs.fClassInfo);
144 fFirstTime = rhs.fFirstTime;
145 fDescend = rhs.fDescend;
149 fBaseInfo =
new TClingClassInfo(*rhs.fBaseInfo);
150 fIterStack = rhs.fIterStack;
151 fOffset = rhs.fOffset;
152 fClassInfoOwnership =
true;
157 TClingClassInfo *TClingBaseClassInfo::GetBase()
const
166 TClingBaseClassInfo::GenerateBaseOffsetFunction(TClingClassInfo * fromDerivedClass,
167 TClingClassInfo* toBaseClass,
168 void* address,
bool isDerivedObject)
const
176 if (fInterp->isInSyntaxOnlyMode())
180 const clang::RecordDecl* fromDerivedDecl
181 = dyn_cast<clang::RecordDecl>(fromDerivedClass->GetDecl());
182 if (!fromDerivedDecl) {
183 ::Error(
"TClingBaseClassInfo::GenerateBaseOffsetFunction",
184 "Offset of non-class %s is ill-defined!", fromDerivedClass->Name());
187 const clang::RecordDecl* toBaseDecl
188 = dyn_cast<clang::RecordDecl>(toBaseClass->GetDecl());
190 ::Error(
"TClingBaseClassInfo::GenerateBaseOffsetFunction",
191 "Offset of non-class %s is ill-defined!", toBaseClass->Name());
199 buf <<
"h" << fromDerivedDecl;
201 buf <<
"h" << toBaseDecl;
202 wrapper_name = buf.str();
206 if (!fInterp->getAddressOfGlobal(wrapper_name)) {
208 string fromDerivedClassName;
209 clang::QualType QTDerived(fromDerivedClass->GetType(), 0);
210 ROOT::TMetaUtils::GetFullyQualifiedTypeName(fromDerivedClassName,
211 QTDerived, *fInterp);
212 string toBase_class_name;
213 clang::QualType QTtoBase(toBaseClass->GetType(), 0);
214 ROOT::TMetaUtils::GetFullyQualifiedTypeName(toBase_class_name,
217 llvm::raw_string_ostream buf(code);
218 buf <<
"extern \"C\" long " + wrapper_name +
"(void* address, bool isDerivedObject) {\n"
220 <<
" " << fromDerivedClassName <<
" *fromDerived;"
221 <<
" if (isDerivedObject) {"
222 <<
" fromDerived = (" << fromDerivedClassName <<
"*)address;\n"
224 <<
" fromDerived = dynamic_cast<" << fromDerivedClassName <<
"*>((" << toBase_class_name <<
"*)address);\n"
226 <<
" if (!fromDerived) {\n"
229 <<
" " << toBase_class_name <<
" *toBase = fromDerived;\n"
230 <<
" return ((long)toBase - (long)fromDerived);\n}\n";
234 void* f = fInterp->compileFunction(wrapper_name, code,
true ,
237 ::Error(
"TClingBaseClassInfo::GenerateBaseOffsetFunction",
238 "Compilation failed!");
242 return (OffsetPtrFunc_t) f;
245 bool TClingBaseClassInfo::IsValid()
const
249 fClassInfo->IsValid() &&
255 fBaseInfo->IsValid();
258 int TClingBaseClassInfo::InternalNext(
int onlyDirect)
261 if (!fDecl || !fIter ||
262 (fIter == llvm::dyn_cast<clang::CXXRecordDecl>(fDecl)->bases_end())) {
273 else if (!onlyDirect && fDescend) {
278 cling::Interpreter::PushTransactionRAII RAII(fInterp);
280 const clang::RecordType *Ty = fIter->getType()->
281 getAs<clang::RecordType>();
284 clang::CXXRecordDecl *Base = llvm::cast<clang::CXXRecordDecl>(
285 Ty->getDecl()->getDefinition());
286 clang::ASTContext &Context = Base->getASTContext();
287 const clang::RecordDecl *RD = llvm::dyn_cast<clang::RecordDecl>(fDecl);
288 const clang::ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
289 int64_t offset = Layout.getBaseClassOffset(Base).getQuantity();
290 fOffset +=
static_cast<long>(offset);
291 fIterStack.push_back(std::make_pair(std::make_pair(fDecl, fIter),
292 static_cast<long>(offset)));
294 fIter = Base->bases_begin();
302 (fIter == llvm::dyn_cast<clang::CXXRecordDecl>(fDecl)->bases_end()) &&
306 fDecl = fIterStack.back().first.first;
307 fIter = fIterStack.back().first.second;
308 fOffset -= fIterStack.back().second;
309 fIterStack.pop_back();
313 if (fIter == llvm::dyn_cast<clang::CXXRecordDecl>(fDecl)->bases_end()) {
322 const clang::TagType *Ty = fIter->getType()->getAs<clang::TagType>();
328 const clang::CXXRecordDecl *Base =
329 llvm::cast_or_null<clang::CXXRecordDecl>(Ty->getDecl()->
337 if (!onlyDirect && Base->getNumBases()) {
342 clang::QualType bType = ROOT::TMetaUtils::ReSubstTemplateArg(fIter->getType(),fClassInfo->GetType());
343 fBaseInfo =
new TClingClassInfo(fInterp, *bType);
349 int TClingBaseClassInfo::Next(
int onlyDirect)
351 return InternalNext(onlyDirect);
354 int TClingBaseClassInfo::Next()
361 static clang::CharUnits computeOffsetHint(clang::ASTContext &Context,
362 const clang::CXXRecordDecl *Src,
363 const clang::CXXRecordDecl *Dst,
364 cling::Interpreter* interp)
366 clang::CXXBasePaths Paths(
true,
true,
371 if (!Dst->isDerivedFrom(Src, Paths))
372 return clang::CharUnits::fromQuantity(-2);
374 unsigned NumPublicPaths = 0;
375 clang::CharUnits Offset;
378 for (clang::CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
383 for (clang::CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
386 if (J->Base->isVirtual())
387 return clang::CharUnits::fromQuantity(-1);
389 if (NumPublicPaths > 1)
393 cling::Interpreter::PushTransactionRAII RAII(interp);
394 const clang::ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
395 Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
400 if (NumPublicPaths == 0)
401 return clang::CharUnits::fromQuantity(-2);
404 if (NumPublicPaths > 1)
405 return clang::CharUnits::fromQuantity(-3);
412 ptrdiff_t TClingBaseClassInfo::Offset(
void * address,
bool isDerivedObject)
const
420 const clang::CXXRecordDecl* Base =
421 llvm::cast_or_null<clang::CXXRecordDecl>(fBaseInfo->GetDecl());
427 if (!(Property() & kIsVirtualBase)) {
428 clang::ASTContext& Context = Base->getASTContext();
429 const clang::CXXRecordDecl* RD = llvm::dyn_cast<clang::CXXRecordDecl>(fDecl);
434 long clang_val = computeOffsetHint(Context, Base, RD, fInterp).getQuantity();
435 if (clang_val == -2 || clang_val == -3) {
443 PrintingPolicy Policy(fBaseInfo->GetDecl()->getASTContext().
444 getPrintingPolicy());
445 llvm::raw_string_ostream stream(buf);
446 ((
const clang::NamedDecl*)fBaseInfo->GetDecl())
447 ->getNameForDiagnostic(stream, Policy,
true);
452 ((
const clang::NamedDecl*)fClassInfo->GetDecl())
453 ->getNameForDiagnostic(stream, Policy,
true);
457 if (clang_val == -2) {
458 ::Error(
"TClingBaseClassInfo::Offset",
459 "The class %s does not derive from the base %s.",
460 derivedName.Data(), baseName.Data());
463 ::Error(
"TClingBaseClassInfo::Offset",
464 "There are multiple paths from derived class %s to base class %s.",
465 derivedName.Data(), baseName.Data());
469 fClassInfo->AddBaseOffsetValue(fBaseInfo->GetDecl(), clang_val);
474 ::Error(
"TClingBaseClassInfo::Offset",
"The address of the object for virtual base offset calculation is not valid.");
479 OffsetPtrFunc_t executableFunc = GenerateBaseOffsetFunction(fClassInfo, fBaseInfo, address, isDerivedObject);
480 if (executableFunc) {
481 fClassInfo->AddBaseOffsetFunction(fBaseInfo->GetDecl(), executableFunc);
482 return (*executableFunc)(address, isDerivedObject);
489 long TClingBaseClassInfo::Property()
const
496 if (fDecl == fClassInfo->GetDecl()) {
497 property |= kIsDirectInherit;
500 const clang::CXXRecordDecl* CRD
501 = llvm::dyn_cast<CXXRecordDecl>(fDecl);
502 const clang::CXXRecordDecl* BaseCRD
503 = llvm::dyn_cast<CXXRecordDecl>(fBaseInfo->GetDecl());
504 if (!CRD || !BaseCRD) {
505 ::Error(
"TClingBaseClassInfo::Property",
506 "The derived class or the base class do not have a CXXRecordDecl.");
510 clang::CXXBasePaths Paths(
false,
true,
512 if (!CRD->isDerivedFrom(BaseCRD, Paths)) {
515 ::Error(
"TClingBaseClassInfo",
"Class not derived from given base.");
517 if (Paths.getDetectedVirtual()) {
518 property |= kIsVirtualBase;
521 clang::AccessSpecifier AS = clang::AS_public;
523 for (clang::CXXBasePaths::const_paths_iterator IB = Paths.begin(), EB = Paths.end();
524 AS != clang::AS_private && IB != EB; ++IB) {
525 switch (IB->Access) {
527 case clang::AS_public:
break;
528 case clang::AS_protected: AS = clang::AS_protected;
break;
529 case clang::AS_private: AS = clang::AS_private;
break;
530 case clang::AS_none:
break;
534 case clang::AS_public:
535 property |= kIsPublic;
537 case clang::AS_protected:
538 property |= kIsProtected;
540 case clang::AS_private:
541 property |= kIsPrivate;
550 long TClingBaseClassInfo::Tagnum()
const
555 return fBaseInfo->Tagnum();
558 void TClingBaseClassInfo::FullName(std::string &output,
const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
const
564 fBaseInfo->FullName(output,normCtxt);
567 const char* TClingBaseClassInfo::Name()
const
572 return fBaseInfo->Name();
575 const char* TClingBaseClassInfo::TmpltName()
const
580 return fBaseInfo->TmpltName();