Skip to content

Commit

Permalink
[cling] CreateNestedNameSpecifierForScopeOf needs specialization cont…
Browse files Browse the repository at this point in the history
…ext:

Instead of picking a "random" (the first) specialization when building the name
of a non-dependent member type of a template, pick the one that corresponds to
the "current" specialization. As CreateNestedNameSpecifierForScopeOf cannot know
what's "current", this context needs to be passed down / propagated.

Add a couple of asserts that the context is provided when needed, and is a
template specialization that matches the type at hand.

This fixes root-project#7955.
  • Loading branch information
Axel-Naumann authored and silverweed committed Aug 14, 2024
1 parent 625a037 commit 1b6ddec
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 99 deletions.
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
14 changes: 9 additions & 5 deletions core/clingutils/src/TClingUtils.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1473,6 +1473,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);

// 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 +1498,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 +3490,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 +3503,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 +3513,8 @@ void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr,

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

////////////////////////////////////////////////////////////////////////////////
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
13 changes: 9 additions & 4 deletions interpreter/cling/include/cling/Utils/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace clang {
class ASTContext;
class ClassTemplateSpecializationDecl;
class Expr;
class Decl;
class DeclContext;
Expand Down Expand Up @@ -301,7 +302,8 @@ namespace utils {
/// returned.
///\param[in] Ctx - the ASTContext to be used.
clang::QualType GetFullyQualifiedType(clang::QualType QT,
const clang::ASTContext& Ctx);
const clang::ASTContext& Ctx,
const clang::ClassTemplateSpecializationDecl* Spec = nullptr);

///\brief Get the fully qualified name for a type. This includes full
/// qualification of all template parameters etc.
Expand All @@ -310,7 +312,8 @@ namespace utils {
/// returned.
///\param[in] Ctx - the ASTContext to be used.
std::string GetFullyQualifiedName(clang::QualType QT,
const clang::ASTContext &Ctx);
const clang::ASTContext &Ctx,
const clang::ClassTemplateSpecializationDecl* Spec = nullptr);

///\brief Create a NestedNameSpecifier for Namesp and its enclosing
/// scopes.
Expand All @@ -332,7 +335,8 @@ namespace utils {
/// qualified names.
clang::NestedNameSpecifier*
CreateNestedNameSpecifier(const clang::ASTContext& Ctx,
const clang::TagDecl *TD, bool FullyQualify);
const clang::TagDecl *TD, bool FullyQualify,
const clang::ClassTemplateSpecializationDecl* Spec = nullptr);

///\brief Create a NestedNameSpecifier for TypedefDecl and its enclosing
/// scopes.
Expand All @@ -345,7 +349,8 @@ namespace utils {
clang::NestedNameSpecifier*
CreateNestedNameSpecifier(const clang::ASTContext& Ctx,
const clang::TypedefNameDecl *TD,
bool FullyQualify);
bool FullyQualify,
const clang::ClassTemplateSpecializationDecl* Spec = nullptr);

///\brief Create a NestedNameSpecifier for UsingShadowDecl and its enclosing
/// scopes.
Expand Down
21 changes: 19 additions & 2 deletions interpreter/cling/lib/Interpreter/ForwardDeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ namespace cling {
}

void ForwardDeclPrinter::Visit(clang::QualType QT) {
QT = utils::TypeName::GetFullyQualifiedType(QT, m_Ctx);
QT = utils::TypeName::GetFullyQualifiedType(QT, m_Ctx,
m_SpecContextStack.empty() ? nullptr
: m_SpecContextStack.top());
Visit(QT.getTypePtr());
}

Expand Down Expand Up @@ -938,7 +940,9 @@ namespace cling {
}
if (!ArgQT.isNull()) {
QualType ArgFQQT
= utils::TypeName::GetFullyQualifiedType(ArgQT, m_Ctx);
= utils::TypeName::GetFullyQualifiedType(ArgQT, m_Ctx,
m_SpecContextStack.empty() ? nullptr
: m_SpecContextStack.top());
Visit(ArgFQQT);
if (m_SkipFlag) {
skipDecl(nullptr, "type template param default failed");
Expand Down Expand Up @@ -1094,6 +1098,19 @@ namespace cling {
// return;
// }

struct PopStackRAII{
std::stack<ClassTemplateSpecializationDecl*> &m_Stk;
PopStackRAII(std::stack<ClassTemplateSpecializationDecl*> &stk,
ClassTemplateSpecializationDecl* D):
m_Stk(stk)
{
m_Stk.push(D);
}
~PopStackRAII() {
m_Stk.pop();
}
} popStackRAII(m_SpecContextStack, D);

const TemplateArgumentList& iargs = D->getTemplateInstantiationArgs();
for (const TemplateArgument& TA: iargs.asArray()) {
VisitTemplateArgument(TA);
Expand Down
1 change: 1 addition & 0 deletions interpreter/cling/lib/Interpreter/ForwardDeclPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ namespace cling {

llvm::DenseMap<const clang::Decl*, bool> m_Visited; // fwd decl success
std::stack<llvm::raw_ostream*> m_StreamStack;
std::stack<clang::ClassTemplateSpecializationDecl*> m_SpecContextStack;
std::set<llvm::StringRef> m_BuiltinNames;
IgnoreFilesFunc_t m_IgnoreFile; // Call back to ignore some top level files.

Expand Down
Loading

0 comments on commit 1b6ddec

Please sign in to comment.