Skip to content
Open
6 changes: 4 additions & 2 deletions core/clingutils/res/TClingUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -613,12 +613,14 @@ static inline std::string DemangleNameForDlsym(const std::string& name)
//______________________________________________________________________________
// Return the type with all parts fully qualified (most typedefs),
// including template arguments, appended to name.
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter);
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter,
const clang::ClassTemplateSpecializationDecl *Spec = nullptr);

//______________________________________________________________________________
// Return the type with all parts fully qualified (most typedefs),
// including template arguments, appended to name, without using the interpreter
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const clang::ASTContext &);
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const clang::ASTContext &,
const clang::ClassTemplateSpecializationDecl *Spec = nullptr);

//______________________________________________________________________________
// Return the type normalized for ROOT,
Expand Down
17 changes: 11 additions & 6 deletions core/clingutils/src/TClingUtils.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,8 @@ bool ROOT::TMetaUtils::HasCustomConvStreamerMemberFunction(const AnnotatedRecord

void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::QualType &type, const clang::NamedDecl &forcontext)
{
ROOT::TMetaUtils::GetFullyQualifiedTypeName(qual_name, type, forcontext.getASTContext());
ROOT::TMetaUtils::GetFullyQualifiedTypeName(qual_name, type, forcontext.getASTContext(),
llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(&forcontext));
}

//----
Expand Down Expand Up @@ -1473,6 +1474,7 @@ static void CreateNameTypeMap(const clang::CXXRecordDecl &cl, ROOT::MembersTypeM
std::string typenameStr;

const clang::ASTContext& astContext = cl.getASTContext();
auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&cl);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this example breaks some assumptions in this PR.

#include <vector>
#include <string>
#include <stdint.h>

template <class T>
class MEtoEDM {
public:
  typedef std::vector<uint32_t> TagList;

  struct MEtoEDMObject {
    std::string name;
    TagList tags;
    T object;
  };
};

If you can reproduce that crash with a test using the example that'd be a good step forward.

#0  0x00007fffe88f652f in raise () from /lib64/libc.so.6
#1  0x00007fffe88c9e65 in abort () from /lib64/libc.so.6
#2  0x00007fffe88c9d39 in __assert_fail_base.cold.0 () from /lib64/libc.so.6
#3  0x00007fffe88eee86 in __assert_fail () from /lib64/libc.so.6
#4  0x00007fffeaef3d10 in cling::utils::CreateNestedNameSpecifierForScopeOf (Ctx=..., decl=0x3d176f8, FullyQualified=true, Spec=0x0)
    at /data/cmsbld/jenkins/workspace/ib-run-pr-tests/testBuildDir/BUILD/el8_amd64_gcc12/lcg/root/6.33.01-48fd78c793bc73bd3f87499c5ca7bf90/root-6.33.01/interpreter/cling/lib/Utils/AST.cpp:1561
#5  0x00007fffeaef3f03 in cling::utils::CreateNestedNameSpecifierForScopeOf (Ctx=..., TypePtr=0x3d17a30, FullyQualified=true, 
    Spec=0x0)
    at /data/cmsbld/jenkins/workspace/ib-run-pr-tests/testBuildDir/BUILD/el8_amd64_gcc12/lcg/root/6.33.01-48fd78c793bc73bd3f87499c5ca7bf90/root-6.33.01/interpreter/cling/lib/Utils/AST.cpp:1621
#6  0x00007fffeaef4573 in cling::utils::TypeName::GetFullyQualifiedType (QT=..., Ctx=..., Spec=0x0)
    at /data/cmsbld/jenkins/workspace/ib-run-pr-tests/testBuildDir/BUILD/el8_amd64_gcc12/lcg/root/6.33.01-48fd78c793bc73bd3f87499c5ca7bf90/root-6.33.01/interpreter/cling/lib/Utils/AST.cpp:1760
#7  0x00007fffeaef478e in cling::utils::TypeName::GetFullyQualifiedName[abi:cxx11](clang::QualType, clang::ASTContext const&, clang::ClassTemplateSpecializationDecl const*) (QT=..., Ctx=..., Spec=0x0)
    at /data/cmsbld/jenkins/workspace/ib-run-pr-tests/testBuildDir/BUILD/el8_amd64_gcc12/lcg/root/6.33.01-48fd78c793bc73bd3f87499c5ca7bf90/root-6.33.01/interpreter/cling/lib/Utils/AST.cpp:1805
#8  0x00007fffea825603 in ROOT::TMetaUtils::GetFullyQualifiedTypeName (typenamestr="", qtype=..., astContext=..., Spec=0x0)
    at /data/cmsbld/jenkins/workspace/ib-run-pr-tests/testBuildDir/BUILD/el8_amd64_gcc12/lcg/root/6.33.01-48fd78c793bc73bd3f87499c5ca7bf90/root-6.33.01/core/clingutils/src/TClingUtils.cxx:3497
#9  0x00007fffea81c1ef in CreateNameTypeMap (cl=..., nameType=std::map with 1 element = {...})
    at /data/cmsbld/jenkins/workspace/ib-run-pr-tests/testBuildDir/BUILD/el8_amd64_gcc12/lcg/root/6.33.01-48fd78c793bc73bd3f87499c5ca7bf90/root-6.33.01/core/clingutils/src/TClingUtils.cxx:1502
#10 0x00007fffea81d7a2 in ROOT::TMetaUtils::WriteClassInit (finalString=..., cl=..., decl=0x3d5f6c8, interp=..., normCtxt=..., 
    ctorTypes=std::__cxx11::list = {...}, needCollectionProxy=@0x7ffffffef3d7: false)
    at /data/cmsbld/jenkins/workspace/ib-run-pr-tests/testBuildDir/BUILD/el8_amd64_gcc12/lcg/root/6.33.01-48fd78c793bc73bd3f87499c5ca7

That is, we introduce a ClassTemplateSpecializationDecl which could be nullptr and yet we will still have a class template. In this line here we get:

(gdb) p cl.getDescribedTemplate()
$15 = (clang::TemplateDecl *) 0x0
(gdb) p cl.getDescribedClassTemplate()
$16 = (clang::ClassTemplateDecl *) 0x0
(gdb) p cl.getTemplateSpecializationKind () 
$17 = clang::TSK_ImplicitInstantiation

p cl.getInstantiatedFromMemberClass () will get us the outer class will still not be the class template specialization decl.

I think we are trying to get the template pattern of the outer class asking its nested class and that's probably not a good idea. I am not entirely sure what this pull request intends to do, looks very hacky anyways, you can probably get away by asking if the class is nested.

I think this PR is quite messy and will require a lot of work to make it consistent and mergeable.


// Loop over the non static data member.
for(clang::RecordDecl::field_iterator field_iter = cl.field_begin(), end = cl.field_end();
Expand All @@ -1497,7 +1499,7 @@ static void CreateNameTypeMap(const clang::CXXRecordDecl &cl, ROOT::MembersTypeM
}
}

ROOT::TMetaUtils::GetFullyQualifiedTypeName(typenameStr, fieldType, astContext);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(typenameStr, fieldType, astContext, CTSD);
nameType[field_iter->getName().str()] = ROOT::Internal::TSchemaType(typenameStr.c_str(),dims.str().c_str());
}

Expand Down Expand Up @@ -3489,9 +3491,10 @@ std::string ROOT::TMetaUtils::GetFileName(const clang::Decl& decl,

void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr,
const clang::QualType &qtype,
const clang::ASTContext &astContext)
const clang::ASTContext &astContext,
const clang::ClassTemplateSpecializationDecl *Spec /*= nullptr*/)
{
std::string fqname = cling::utils::TypeName::GetFullyQualifiedName(qtype, astContext);
std::string fqname = cling::utils::TypeName::GetFullyQualifiedName(qtype, astContext, Spec);
TClassEdit::TSplitType splitname(fqname.c_str(),
(TClassEdit::EModType)(TClassEdit::kLong64 | TClassEdit::kDropStd | TClassEdit::kDropStlDefault | TClassEdit::kKeepOuterConst));
splitname.ShortType(typenamestr,TClassEdit::kDropStd | TClassEdit::kDropStlDefault | TClassEdit::kKeepOuterConst);
Expand All @@ -3501,7 +3504,8 @@ void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr,

void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr,
const clang::QualType &qtype,
const cling::Interpreter &interpreter)
const cling::Interpreter &interpreter,
const clang::ClassTemplateSpecializationDecl *Spec /*= nullptr*/)
{
// We need this because GetFullyQualifiedTypeName is triggering deserialization
// This calling the same name function GetFullyQualifiedTypeName, but this should stay here because
Expand All @@ -3510,7 +3514,8 @@ void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr,

GetFullyQualifiedTypeName(typenamestr,
qtype,
interpreter.getCI()->getASTContext());
interpreter.getCI()->getASTContext(),
Spec);
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
27 changes: 9 additions & 18 deletions core/dictgen/res/DictSelectionReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,25 +260,16 @@ class DictSelectionReader : public clang::RecursiveASTVisitor<DictSelectionReade
std::unordered_set<std::string> fUnsplittableMembers {};
};

inline bool
InSelectionNamespace(const clang::RecordDecl &,
const std::string &str =
""); ///< Check if in the ROOT::Meta::Selection namespace
inline bool FirstPass(const clang::RecordDecl &); ///< First pass on the AST
inline bool SecondPass(const clang::RecordDecl &); ///< Second pass on the AST, using the information of the first one
inline void
ManageFields(const clang::RecordDecl &,
const std::string &,
ClassSelectionRule &,
bool); ///< Take care of the class fields
inline void
ManageBaseClasses(const clang::CXXRecordDecl &, const std::string &, bool &); ///< Take care of the class bases
bool InSelectionNamespace(const clang::RecordDecl &,
const std::string &str = ""); ///< Check if in the ROOT::Meta::Selection namespace
bool FirstPass(const clang::RecordDecl &); ///< First pass on the AST
bool SecondPass(const clang::RecordDecl &); ///< Second pass on the AST, using the information of the first one
void ManageFields(const clang::RecordDecl &, const std::string &,
ClassSelectionRule &, bool); ///< Take care of the class fields
void ManageBaseClasses(const clang::CXXRecordDecl &, const std::string &, bool &); ///< Take care of the class bases
template <class T>
inline unsigned int ExtractTemplateArgValue(
const T &,
const std::string &); ///< Extract the value of the template parameter
inline const clang::TemplateArgumentList *GetTmplArgList(
const clang::CXXRecordDecl &); ///< Get the template arguments list if any
unsigned int ExtractTemplateArgValue(const T &, const std::string &); ///< Extract the value of the template parameter
const clang::TemplateArgumentList *GetTmplArgList(const clang::CXXRecordDecl &); ///< Get the template arguments list if any

std::string PatternifyName(const std::string &className); ///< Transform instance name in pattern for selection
void GetPointeeType(std::string &typeName); ///< Get name of the pointee type
Expand Down
15 changes: 15 additions & 0 deletions core/dictgen/src/DictSelectionReader.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -383,12 +383,27 @@ bool DictSelectionReader::SecondPass(const clang::RecordDecl &recordDecl)

bool DictSelectionReader::VisitRecordDecl(clang::RecordDecl *recordDecl)
{
if (auto CXXRD = llvm::dyn_cast<clang::CXXRecordDecl>(recordDecl)) {
if (CXXRD->getDescribedClassTemplate()) {
// this is a member of a template; ignore: dictionaries can only
// select instances / specializations.
return true;
}
}
if (auto CXXRD = llvm::dyn_cast<clang::CXXRecordDecl>(recordDecl->getDeclContext())) {
if (CXXRD->getDescribedClassTemplate()) {
// this is a member of a template; ignore: dictionaries can only
// select instances / specializations.
return true;
}
}
if (fIsFirstPass)
return FirstPass(*recordDecl);
else
return SecondPass(*recordDecl);
}


////////////////////////////////////////////////////////////////////////////////

/**
Expand Down
4 changes: 3 additions & 1 deletion core/metacling/src/TClingDataMemberInfo.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ from the Clang C++ compiler, not CINT.
#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
Expand Down Expand Up @@ -586,7 +587,8 @@ const char *TClingDataMemberInfo::TypeName() const
// if (we_need_to_do_the_subst_because_the_class_is_a_template_instance_of_double32_t)
vdType = ROOT::TMetaUtils::ReSubstTemplateArg(vdType, GetClassAsType() );

ROOT::TMetaUtils::GetFullyQualifiedTypeName(buf, vdType, *fInterp);
auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(vd->getDeclContext());
ROOT::TMetaUtils::GetFullyQualifiedTypeName(buf, vdType, *fInterp, CTSD);

return buf.c_str();
}
Expand Down
7 changes: 6 additions & 1 deletion core/metacling/src/TClingMethodArgInfo.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ the Clang C++ compiler, not CINT.
#include "cling/Interpreter/Interpreter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
Expand Down Expand Up @@ -148,6 +149,10 @@ const char *TClingMethodArgInfo::TypeName() const
if (!IsValid()) {
return nullptr;
}
return Type()->Name();

const clang::ClassTemplateSpecializationDecl *spec = nullptr;
if (const auto FD = llvm::cast_or_null<clang::FunctionDecl>(TClingDeclInfo::GetDecl()))
spec = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(FD->getDeclContext());
return Type()->Name(spec);
}

14 changes: 12 additions & 2 deletions core/metacling/src/TClingMethodInfo.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,9 @@ const char *TClingMethodInfo::GetPrototype()
if (const clang::TypeDecl *td = llvm::dyn_cast<clang::TypeDecl>(GetDecl()->getDeclContext())) {
std::string name;
clang::QualType qualType(td->getTypeForDecl(),0);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(name,qualType,*fInterp);
const clang::ClassTemplateSpecializationDecl *spec
= llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(td);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(name, qualType, *fInterp, spec);
buf += name;
buf += "::";
} else if (const clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(FD->getDeclContext())) {
Expand Down Expand Up @@ -688,9 +690,17 @@ const char *TClingMethodInfo::TypeName() const
// The next *two* calls lock the interpreter mutex. Lock here first instead
// of locking/unlocking twice.
R__LOCKGUARD(gInterpreterMutex);
return Type()->Name();
const clang::ClassTemplateSpecializationDecl *spec
= llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(GetDecl()->getDeclContext());
return Type()->Name(spec);
}

std::string TClingMethodInfo::NormalizedName(ROOT::TMetaUtils::TNormalizedCtxt &ctx) const
{
return Type()->NormalizedName(ctx);
}


const char *TClingMethodInfo::Title()
{
if (!IsValid()) {
Expand Down
1 change: 1 addition & 0 deletions core/metacling/src/TClingMethodInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ class TClingMethodInfo final : public TClingDeclInfo {
const char *GetPrototype();
const char *Name() const override;
const char *TypeName() const;
std::string NormalizedName(ROOT::TMetaUtils::TNormalizedCtxt &ctx) const;
const char *Title();
};

Expand Down
5 changes: 3 additions & 2 deletions core/metacling/src/TClingTypeInfo.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ but the type metadata comes from the Clang C++ compiler, not CINT.

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Type.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Frontend/CompilerInstance.h"
Expand Down Expand Up @@ -97,7 +98,7 @@ void TClingTypeInfo::Init(const char *name)

////////////////////////////////////////////////////////////////////////////////

const char *TClingTypeInfo::Name() const
const char *TClingTypeInfo::Name(const clang::ClassTemplateSpecializationDecl *spec) const
{
if (!IsValid()) {
return "";
Expand All @@ -109,7 +110,7 @@ const char *TClingTypeInfo::Name() const
// TODO: This needs to be locked, but the lock cannot be placed in TClingUtils.cxx as it cannot depend from
// TInterpreter.h for the declaration of gInterpreterMutex. Or can it?
R__LOCKGUARD(gInterpreterMutex);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(buf,fQualType,*fInterp);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(buf,fQualType,*fInterp, spec);
return buf.c_str(); // NOLINT
}

Expand Down
7 changes: 6 additions & 1 deletion core/metacling/src/TClingTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@

#include "clang/AST/Type.h"

namespace clang {
class ClassTemplateSpecializationDecl;
}

namespace cling {
class Interpreter;
}
Expand Down Expand Up @@ -65,7 +69,8 @@ class TClingTypeInfo final : public TClingDeclInfo {
void Init(const char *name); // Set type by name.
void Init(clang::QualType ty) { fQualType = ty; }
bool IsValid() const override { return !fQualType.isNull(); }
const char *Name() const override; // Get name of type.
const char *Name() const override { return Name(nullptr); }
const char *Name(const clang::ClassTemplateSpecializationDecl *spec) const; // Get name of type.
long Property() const; // Get properties of type.
int RefType() const; // Get CINT reftype of type.
int Size() const; // Get size in bytes of type.
Expand Down
Loading