Logo ROOT   master
Reference Guide
TClingBaseClassInfo.cxx
Go to the documentation of this file.
1 // @(#)root/core/meta:$Id$
2 // Author: Paul Russo 30/07/2012
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TClingBaseClassInfo
13 
14 Emulation of the CINT BaseClassInfo class.
15 
16 The CINT C++ interpreter provides an interface to metadata about
17 the base classes of a class through the BaseClassInfo class. This
18 class provides the same functionality, using an interface as close
19 as possible to BaseClassInfo but the base class metadata comes from
20 the Clang C++ compiler, not CINT.
21 */
22 
23 #include "TClingBaseClassInfo.h"
24 
25 #include "TClingClassInfo.h"
26 #include "TDictionary.h"
27 #include "TClingUtils.h"
28 
29 #include "TError.h"
30 
31 #include "cling/Interpreter/Interpreter.h"
32 #include "cling/Interpreter/Transaction.h"
33 
34 
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"
42 
43 
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"
48 
49 #include <string>
50 #include <sstream>
51 #include <iostream>
52 
53 using namespace llvm;
54 using namespace clang;
55 using namespace std;
56 
57 TClingBaseClassInfo::TClingBaseClassInfo(cling::Interpreter* interp,
58  TClingClassInfo* ci)
59  : fInterp(interp), fClassInfo(0), fFirstTime(true), fDescend(false),
60  fDecl(0), fIter(0), fBaseInfo(0), fOffset(0L), fClassInfoOwnership(true)
61 {
62  // Constructs a base class iterator on ci; ci == 0 means global scope (which
63  // is meaningless). The derived class info passed in as ci is copied.
64  if (!ci) {
65  fClassInfo = new TClingClassInfo(interp);
66  return;
67  }
68  fClassInfo = new TClingClassInfo(*ci);
69  if (!fClassInfo->GetDecl()) {
70  return;
71  }
72  const clang::CXXRecordDecl* CRD =
73  llvm::dyn_cast<clang::CXXRecordDecl>(fClassInfo->GetDecl());
74  if (!CRD) {
75  // We were initialized with something that is not a class.
76  // FIXME: We should prevent this from happening!
77  return;
78  }
79  fDecl = CRD;
80  {
81  // In particular if the base are templated, this might deserialize.
82  cling::Interpreter::PushTransactionRAII RAII(fInterp);
83  fIter = CRD->bases_begin();
84  }
85 }
86 
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)
92 {
93  // Constructs a single base class base (no iterator) of derived; derived must be != 0.
94  // The derived class info is referenced during the lifetime of the TClingBaseClassInfo.
95  if (!derived->GetDecl()) {
96  return;
97  }
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) {
103  // We were initialized with something that is not a class.
104  // FIXME: We should prevent this from happening!
105  return;
106  }
107 
108  fClassInfo = derived;
109  fDecl = CRD;
110  //CRD->isDerivedFrom(BaseCRD, Paths);
111  // Check that base derives from derived.
112  clang::CXXBasePaths Paths;
113 
114  // CXXRecordDecl::isDerivedFrom can trigger deserialization.
115  cling::Interpreter::PushTransactionRAII RAII(fInterp);
116 
117  if (!CRD->isDerivedFrom(BaseCRD, Paths)) {
118  //Not valid fBaseInfo = 0.
119  return;
120  }
121 
122  fBaseInfo = new TClingClassInfo(*base);
123  fIter = CRD->bases_end();
124 }
125 
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)
130 {
131  // Copies a base class info including the base and derived class infos.
133  fBaseInfo = new TClingClassInfo(*rhs.fBaseInfo);
134 }
135 
137  const TClingBaseClassInfo& rhs)
138 {
139  if (this != &rhs) {
140  fInterp = rhs.fInterp;
142  delete fClassInfo;
144  fFirstTime = rhs.fFirstTime;
145  fDescend = rhs.fDescend;
146  fDecl = rhs.fDecl;
147  fIter = rhs.fIter;
148  delete fBaseInfo;
149  fBaseInfo = new TClingClassInfo(*rhs.fBaseInfo);
150  fIterStack = rhs.fIterStack;
151  fOffset = rhs.fOffset;
152  fClassInfoOwnership = true;
153  }
154  return *this;
155 }
156 
158 {
159  if (!IsValid()) {
160  return 0;
161  }
162  return fBaseInfo;
163 }
164 
167  TClingClassInfo* toBaseClass,
168  void* address, bool isDerivedObject) const
169 {
170  // Generate a function at run-time that would calculate the offset
171  // from the parameter derived class to the parameter toBase class for the
172  // address.
173 
174  // rootcling can trigger this, too, and without CodeGen we cannot use any
175  // offset calculation function.
176  if (fInterp->isInSyntaxOnlyMode())
177  return 0;
178 
179  // Get the dedcls for the two classes.
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());
185  return 0;
186  }
187  const clang::RecordDecl* toBaseDecl
188  = dyn_cast<clang::RecordDecl>(toBaseClass->GetDecl());
189  if (!toBaseDecl) {
190  ::Error("TClingBaseClassInfo::GenerateBaseOffsetFunction",
191  "Offset of non-class %s is ill-defined!", toBaseClass->Name());
192  return 0;
193  }
194 
195  // Make the wrapper name.
196  string wrapper_name;
197  {
198  ostringstream buf;
199  buf << "h" << fromDerivedDecl;
200  buf << '_';
201  buf << "h" << toBaseDecl;
202  wrapper_name = buf.str();
203  }
204  string code;
205  // Check whether the function was already generated.
206  if (!fInterp->getAddressOfGlobal(wrapper_name)) {
207  // Get the class or namespace 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);
215  QTtoBase, *fInterp);
216  // Write the wrapper code.
217  llvm::raw_string_ostream buf(code);
218  buf << "extern \"C\" long " + wrapper_name + "(void* address, bool isDerivedObject) {\n"
219  // If the object is not derived, will downcast to toBase first.
220  << " " << fromDerivedClassName << " *fromDerived;"
221  << " if (isDerivedObject) {"
222  << " fromDerived = (" << fromDerivedClassName << "*)address;\n"
223  << " } else {\n"
224  << " fromDerived = dynamic_cast<" << fromDerivedClassName << "*>((" << toBase_class_name << "*)address);\n"
225  << " }\n"
226  << " if (!fromDerived) {\n"
227  << " return -1; \n"
228  << " }\n"
229  << " " << toBase_class_name << " *toBase = fromDerived;\n"
230  << " return ((long)toBase - (long)fromDerived);\n}\n";
231  }
232 
233  // If we have a GV then compileFunction will use it; empty code is enough.
234  void* f = fInterp->compileFunction(wrapper_name, code, true /*ifUnique*/,
235  false /*withAccessControl*/);
236  if (!f) {
237  ::Error("TClingBaseClassInfo::GenerateBaseOffsetFunction",
238  "Compilation failed!");
239  return 0;
240  }
241 
242  return (OffsetPtrFunc_t) f;
243 }
244 
246 {
247  return
248  // inited with a valid class, and
249  fClassInfo->IsValid() &&
250  // the base class we are iterating over is valid, and
251  fDecl &&
252  // our current base has a TClingClassInfo, and
253  fBaseInfo &&
254  // our current base is a valid class
255  fBaseInfo->IsValid();
256 }
257 
259 {
260  // Exit early if the iterator is already invalid.
261  if (!fDecl || !fIter ||
262  (fIter == llvm::dyn_cast<clang::CXXRecordDecl>(fDecl)->bases_end())) {
263  return 0;
264  }
265 
266  // Advance to the next valid base.
267  while (1) {
268  // Advance the iterator.
269  if (fFirstTime) {
270  // The cint semantics are strange.
271  fFirstTime = false;
272  }
273  else if (!onlyDirect && fDescend) {
274  // We previously processed a base class which itself has bases,
275  // now we process the bases of that base class.
276 
277  // At least getASTRecordLayout() might deserialize.
278  cling::Interpreter::PushTransactionRAII RAII(fInterp);
279  fDescend = false;
280  const clang::RecordType *Ty = fIter->getType()->
281  getAs<clang::RecordType>();
282  // Note: We made sure this would work when we selected the
283  // base for processing.
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)));
293  fDecl = Base;
294  fIter = Base->bases_begin();
295  }
296  else {
297  // Simple case, move on to the next base class specifier.
298  ++fIter;
299  }
300  // Fix it if we went past the end.
301  while (
302  (fIter == llvm::dyn_cast<clang::CXXRecordDecl>(fDecl)->bases_end()) &&
303  fIterStack.size()
304  ) {
305  // All done with this base class.
306  fDecl = fIterStack.back().first.first;
307  fIter = fIterStack.back().first.second;
308  fOffset -= fIterStack.back().second;
309  fIterStack.pop_back();
310  ++fIter;
311  }
312  // Check for final termination.
313  if (fIter == llvm::dyn_cast<clang::CXXRecordDecl>(fDecl)->bases_end()) {
314  // We have reached the end of the direct bases, all done.
315  delete fBaseInfo;
316  fBaseInfo = 0;
317  // Iterator is now invalid.
318  return 0;
319  }
320  // Check if current base class is a dependent type, that is, an
321  // uninstantiated template class.
322  const clang::TagType *Ty = fIter->getType()->getAs<clang::TagType>();
323  if (!Ty) {
324  // A dependent type (uninstantiated template), skip it.
325  continue;
326  }
327  // Check if current base class has a definition.
328  const clang::CXXRecordDecl *Base =
329  llvm::cast_or_null<clang::CXXRecordDecl>(Ty->getDecl()->
330  getDefinition());
331  if (!Base) {
332  // No definition yet (just forward declared), skip it.
333  continue;
334  }
335  // Now that we are going to return this base, check to see if
336  // we need to examine its bases next call.
337  if (!onlyDirect && Base->getNumBases()) {
338  fDescend = true;
339  }
340  // Update info for this base class.
341  delete fBaseInfo;
342  clang::QualType bType = ROOT::TMetaUtils::ReSubstTemplateArg(fIter->getType(),fClassInfo->GetType());
343  fBaseInfo = new TClingClassInfo(fInterp, *bType);
344  // Iterator is now valid.
345  return 1;
346  }
347 }
348 
349 int TClingBaseClassInfo::Next(int onlyDirect)
350 {
351  return InternalNext(onlyDirect);
352 }
353 
355 {
356  return Next(1);
357 }
358 
359 // This function is updating original one on http://clang.llvm.org/doxygen/CGExprCXX_8cpp_source.html#l01647
360 // To fit the needs.
361 static clang::CharUnits computeOffsetHint(clang::ASTContext &Context,
362  const clang::CXXRecordDecl *Src,
363  const clang::CXXRecordDecl *Dst,
364  cling::Interpreter* interp)
365 {
366  clang::CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
367  /*DetectVirtual=*/false);
368 
369  // If Dst is not derived from Src we can skip the whole computation below and
370  // return that Src is not a public base of Dst. Record all inheritance paths.
371  if (!Dst->isDerivedFrom(Src, Paths))
372  return clang::CharUnits::fromQuantity(-2);
373 
374  unsigned NumPublicPaths = 0;
375  clang::CharUnits Offset;
376 
377  // Now walk all possible inheritance paths.
378  for (clang::CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
379  I != E; ++I) {
380 
381  ++NumPublicPaths;
382 
383  for (clang::CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
384  // If the path contains a virtual base class we can't give any hint.
385  // -1: no hint.
386  if (J->Base->isVirtual())
387  return clang::CharUnits::fromQuantity(-1);
388 
389  if (NumPublicPaths > 1) // Won't use offsets, skip computation.
390  continue;
391 
392  // Accumulate the base class offsets.
393  cling::Interpreter::PushTransactionRAII RAII(interp);
394  const clang::ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
395  Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
396  }
397  }
398 
399  // -2: Src is not a public base of Dst.
400  if (NumPublicPaths == 0)
401  return clang::CharUnits::fromQuantity(-2);
402 
403  // -3: Src is a multiple public base type but never a virtual base type.
404  if (NumPublicPaths > 1)
405  return clang::CharUnits::fromQuantity(-3);
406 
407  // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
408  // Return the offset of Src from the origin of Dst.
409  return Offset;
410  }
411 
412 ptrdiff_t TClingBaseClassInfo::Offset(void * address, bool isDerivedObject) const
413 {
414  // Compute the offset of the derived class to the base class.
415 
416  if (!IsValid()) {
417  return -1;
418  }
419  // Check if current base class has a definition.
420  const clang::CXXRecordDecl* Base =
421  llvm::cast_or_null<clang::CXXRecordDecl>(fBaseInfo->GetDecl());
422  if (!Base) {
423  // No definition yet (just forward declared), invalid.
424  return -1;
425  }
426  // If the base class has no virtual inheritance.
427  if (!(Property() & kIsVirtualBase)) {
428  clang::ASTContext& Context = Base->getASTContext();
429  const clang::CXXRecordDecl* RD = llvm::dyn_cast<clang::CXXRecordDecl>(fDecl);
430  if (!RD) {
431  // No RecordDecl for the class.
432  return -1;
433  }
434  long clang_val = computeOffsetHint(Context, Base, RD, fInterp).getQuantity();
435  if (clang_val == -2 || clang_val == -3) {
436  TString baseName;
437  TString derivedName;
438  {
439  // Need TNormalizedCtxt otherwise...
440  // Note: should we really be issuing a message here? Shouldn't
441  // the caller check and issue the message?
442  std::string buf;
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, /*Qualified=*/true);
448  stream.flush();
449  baseName = buf;
450 
451  buf.clear();
452  ((const clang::NamedDecl*)fClassInfo->GetDecl())
453  ->getNameForDiagnostic(stream, Policy, /*Qualified=*/true);
454  stream.flush();
455  derivedName = buf;
456  }
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());
461  } else {
462  // clang_val == -3
463  ::Error("TClingBaseClassInfo::Offset",
464  "There are multiple paths from derived class %s to base class %s.",
465  derivedName.Data(), baseName.Data());
466  }
467  clang_val = -1;
468  }
470  return clang_val;
471  }
472  // Verify the address of the instantiated object
473  if (!address) {
474  ::Error("TClingBaseClassInfo::Offset", "The address of the object for virtual base offset calculation is not valid.");
475  return -1;
476  }
477 
478  // Virtual inheritance case
479  OffsetPtrFunc_t executableFunc = GenerateBaseOffsetFunction(fClassInfo, fBaseInfo, address, isDerivedObject);
480  if (executableFunc) {
481  fClassInfo->AddBaseOffsetFunction(fBaseInfo->GetDecl(), executableFunc);
482  return (*executableFunc)(address, isDerivedObject);
483  }
484 
485  return -1;
486 }
487 
488 
490 {
491  if (!IsValid()) {
492  return 0L;
493  }
494  long property = 0L;
495 
496  if (fDecl == fClassInfo->GetDecl()) {
497  property |= kIsDirectInherit;
498  }
499 
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.");
507  return property;
508  }
509 
510  clang::CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
511  /*DetectVirtual=*/true);
512  if (!CRD->isDerivedFrom(BaseCRD, Paths)) {
513  // Error really unexpected here, because construction / iteration guarantees
514  //inheritance;
515  ::Error("TClingBaseClassInfo", "Class not derived from given base.");
516  }
517  if (Paths.getDetectedVirtual()) {
518  property |= kIsVirtualBase;
519  }
520 
521  clang::AccessSpecifier AS = clang::AS_public;
522  // Derived: public Mid; Mid : protected Base: Derived inherits protected Base?
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) {
526  // keep AS unchanged?
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;
531  }
532  }
533  switch (AS) {
534  case clang::AS_public:
535  property |= kIsPublic;
536  break;
537  case clang::AS_protected:
538  property |= kIsProtected;
539  break;
540  case clang::AS_private:
541  property |= kIsPrivate;
542  break;
543  case clang::AS_none:
544  // IMPOSSIBLE
545  break;
546  }
547  return property;
548 }
549 
551 {
552  if (!IsValid()) {
553  return -1L;
554  }
555  return fBaseInfo->Tagnum();
556 }
557 
559 {
560  if (!IsValid()) {
561  output.clear();
562  return;
563  }
564  fBaseInfo->FullName(output,normCtxt);
565 }
566 
567 const char* TClingBaseClassInfo::Name() const
568 {
569  if (!IsValid()) {
570  return 0;
571  }
572  return fBaseInfo->Name();
573 }
574 
576 {
577  if (!IsValid()) {
578  return 0;
579  }
580  return fBaseInfo->TmpltName();
581 }
582 
RooCmdArg Offset(Bool_t flag=kTRUE)
void AddBaseOffsetValue(const clang::Decl *decl, ptrdiff_t offset)
Definition: TString.h:845
const char * TmpltName() const
std::vector< std::pair< std::pair< const clang::Decl *, clang::CXXRecordDecl::base_class_const_iterator >, long > > fIterStack
static clang::CharUnits computeOffsetHint(clang::ASTContext &Context, const clang::CXXRecordDecl *Src, const clang::CXXRecordDecl *Dst, cling::Interpreter *interp)
clang::QualType ReSubstTemplateArg(clang::QualType input, const clang::Type *instance)
Check if &#39;input&#39; or any of its template parameter was substituted when instantiating the class templa...
Basic string class.
Definition: TString.h:131
#define f(i)
Definition: RSha256.hxx:104
TClingBaseClassInfo & operator=(const TClingBaseClassInfo &)
virtual bool IsValid() const
STL namespace.
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
TClingBaseClassInfo(cling::Interpreter *, TClingClassInfo *)
RooCmdArg Layout(Double_t xmin, Double_t xmax=0.99, Double_t ymin=0.95)
ptrdiff_t(* OffsetPtrFunc_t)(void *, bool)
virtual const char * Name()
TClingClassInfo * fBaseInfo
int InternalNext(int onlyDirect)
void Error(const char *location, const char *msgfmt,...)
const char * Name() const
const char * TmpltName() const
Emulation of the CINT BaseClassInfo class.
void FullName(std::string &output, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
constexpr Double_t E()
Base of natural log: .
Definition: TMath.h:97
virtual const clang::Decl * GetDecl() const
#define Dst
Definition: mesh.h:158
TClingClassInfo * GetBase() const
static constexpr double L
const clang::Decl * fDecl
Emulation of the CINT ClassInfo class.
ptrdiff_t Offset(void *address=0, bool isDerivedObject=true) const
cling::Interpreter * fInterp
clang::CXXRecordDecl::base_class_const_iterator fIter
void FullName(std::string &output, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
#define I(x, y, z)
static void output(int code)
Definition: gifencode.c:226
TClingClassInfo * fClassInfo
void AddBaseOffsetFunction(const clang::Decl *decl, OffsetPtrFunc_t func)
OffsetPtrFunc_t GenerateBaseOffsetFunction(TClingClassInfo *derivedClass, TClingClassInfo *targetClass, void *address, bool isDerivedObject) const
const clang::Type * GetType() const
const char * Data() const
Definition: TString.h:364