Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 122 additions & 102 deletions interpreter/cling/lib/Interpreter/DeclUnloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,22 @@ namespace {
}
}

template <class EntryType>
void removeSpecializationImpl(llvm::FoldingSetVector<EntryType>& Specs,
const EntryType* Entry) {
// Remove only Entry from Specs, keep all others.
llvm::FoldingSetVector<EntryType> Keep;
for (auto& Spec : Specs) {
if (&Spec != Entry) {
// Avoid assertion on add.
Spec.SetNextInBucket(nullptr);
Keep.InsertNode(&Spec);
}
}

std::swap(Specs, Keep);
}

// Template instantiation of templated function first creates a canonical
// declaration and after the actual template specialization. For example:
// template<typename T> T TemplatedF(T t);
Expand All @@ -344,43 +360,18 @@ namespace {
class FunctionTemplateDeclExt : public FunctionTemplateDecl {
public:
static void removeSpecialization(FunctionTemplateDecl* self,
const FunctionDecl* specialization) {
assert(self && specialization && "Cannot be null!");
assert(specialization == specialization->getCanonicalDecl() &&
const FunctionDecl* spec) {
assert(self && spec && "Cannot be null!");
assert(spec == spec->getCanonicalDecl() &&
"Not the canonical specialization!?");
typedef llvm::SmallVector<FunctionDecl*, 4> Specializations;
typedef llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> Set;

FunctionTemplateDeclExt* This = (FunctionTemplateDeclExt*)self;
Specializations specializations;
const Set& specs = This->getCommonPtr()->Specializations;
auto* This = static_cast<FunctionTemplateDeclExt*>(self);
auto& specs = This->getCommonPtr()->Specializations;
removeSpecializationImpl(specs, spec->getTemplateSpecializationInfo());

if (!specs.size()) // nothing to remove
return;

// Collect all the specializations without the one to remove.
for (Set::const_iterator I = specs.begin(), E = specs.end(); I != E;
++I) {
assert(I->getFunction() && "Must have a specialization.");
if (I->getFunction() != specialization)
specializations.push_back(I->getFunction());
}

This->getCommonPtr()->Specializations.clear();

// Readd the collected specializations.
void* InsertPos = nullptr;
FunctionTemplateSpecializationInfo* FTSI = nullptr;
for (size_t i = 0, e = specializations.size(); i < e; ++i) {
FTSI = specializations[i]->getTemplateSpecializationInfo();
assert(FTSI && "Must not be null.");
// Avoid assertion on add.
FTSI->SetNextInBucket(nullptr);
This->addSpecialization(FTSI, InsertPos);
}
#ifndef NDEBUG
const TemplateArgumentList* args =
specialization->getTemplateSpecializationArgs();
const TemplateArgumentList* args = spec->getTemplateSpecializationArgs();
void* InsertPos = nullptr;
assert(!self->findSpecialization(args->asArray(), InsertPos) &&
"Finds the removed decl again!");
#endif
Expand All @@ -399,35 +390,10 @@ namespace {
assert(self && spec && "Cannot be null!");
assert(spec == spec->getCanonicalDecl() &&
"Not the canonical specialization!?");
typedef llvm::SmallVector<ClassTemplateSpecializationDecl*, 4>
Specializations;
typedef llvm::FoldingSetVector<ClassTemplateSpecializationDecl> Set;

ClassTemplateDeclExt* This = (ClassTemplateDeclExt*)self;
Specializations specializations;
Set& specs = This->getCommonPtr()->Specializations;

if (!specs.size()) // nothing to remove
return;

// Collect all the specializations without the one to remove.
for (Set::iterator I = specs.begin(), E = specs.end(); I != E; ++I) {
if (&*I != spec)
specializations.push_back(&*I);
}

This->getCommonPtr()->Specializations.clear();

// Readd the collected specializations.
void* InsertPos = nullptr;
ClassTemplateSpecializationDecl* CTSD = nullptr;
for (size_t i = 0, e = specializations.size(); i < e; ++i) {
CTSD = specializations[i];
assert(CTSD && "Must not be null.");
// Avoid assertion on add.
CTSD->SetNextInBucket(nullptr);
This->AddSpecialization(CTSD, InsertPos);
}
auto* This = static_cast<ClassTemplateDeclExt*>(self);
auto& specs = This->getCommonPtr()->Specializations;
removeSpecializationImpl(specs, spec);
}

static void
Expand All @@ -436,36 +402,41 @@ namespace {
assert(self && spec && "Cannot be null!");
assert(spec == spec->getCanonicalDecl() &&
"Not the canonical specialization!?");
typedef llvm::SmallVector<ClassTemplatePartialSpecializationDecl*, 4>
Specializations;
typedef llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>
Set;

ClassTemplateDeclExt* This = (ClassTemplateDeclExt*)self;
Specializations specializations;
Set& specs = This->getPartialSpecializations();
auto* This = static_cast<ClassTemplateDeclExt*>(self);
auto& specs = This->getPartialSpecializations();
removeSpecializationImpl(specs, spec);
}
};

if (!specs.size()) // nothing to remove
return;
// A template specialization is attached to the list of specialization of
// the templated variable.
//
class VarTemplateDeclExt : public VarTemplateDecl {
public:
static void removeSpecialization(VarTemplateDecl* self,
VarTemplateSpecializationDecl* spec) {
assert(!isa<VarTemplatePartialSpecializationDecl>(spec) &&
"Use removePartialSpecialization");
assert(self && spec && "Cannot be null!");
assert(spec == spec->getCanonicalDecl() &&
"Not the canonical specialization!?");

// Collect all the specializations without the one to remove.
for (Set::iterator I = specs.begin(), E = specs.end(); I != E; ++I) {
if (&*I != spec)
specializations.push_back(&*I);
}
auto* This = static_cast<VarTemplateDeclExt*>(self);
auto& specs = This->getCommonPtr()->Specializations;
removeSpecializationImpl(specs, spec);
}

This->getPartialSpecializations().clear();
static void
removePartialSpecialization(VarTemplateDecl* self,
VarTemplatePartialSpecializationDecl* spec) {
assert(self && spec && "Cannot be null!");
assert(spec == spec->getCanonicalDecl() &&
"Not the canonical specialization!?");

// Readd the collected specializations.
void* InsertPos = nullptr;
ClassTemplatePartialSpecializationDecl* CTPSD = nullptr;
for (size_t i = 0, e = specializations.size(); i < e; ++i) {
CTPSD = specializations[i];
assert(CTPSD && "Must not be null.");
// Avoid assertion on add.
CTPSD->SetNextInBucket(nullptr);
This->AddPartialSpecialization(CTPSD, InsertPos);
}
auto* This = static_cast<VarTemplateDeclExt*>(self);
auto& specs = This->getPartialSpecializations();
removeSpecializationImpl(specs, spec);
}
};
} // end anonymous namespace
Expand Down Expand Up @@ -636,7 +607,7 @@ namespace cling {
return Successful;
}

bool DeclUnloader::VisitFunctionDecl(FunctionDecl* FD) {
bool DeclUnloader::VisitFunctionDecl(FunctionDecl* FD, bool RemoveSpec) {
// The Structors need to be handled differently.
if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD)) {
// Cleanup the module if the transaction was committed and code was
Expand Down Expand Up @@ -696,7 +667,7 @@ namespace cling {
Successful &= VisitRedeclarable(FD, FD->getDeclContext());
Successful &= VisitDeclaratorDecl(FD);

if (FD->isFunctionTemplateSpecialization() && wasCanonical) {
if (RemoveSpec && FD->isFunctionTemplateSpecialization() && wasCanonical) {
// Only the canonical declarations are registered in the list of the
// specializations.
FunctionTemplateDecl* FTD
Expand Down Expand Up @@ -724,6 +695,10 @@ namespace cling {
return Successful;
}

bool DeclUnloader::VisitFunctionDecl(FunctionDecl* FD) {
return VisitFunctionDecl(FD, /*RemoveSpec=*/true);
}

bool DeclUnloader::VisitCXXConstructorDecl(CXXConstructorDecl* CXXCtor) {
// Cleanup the module if the transaction was committed and code was
// generated. This has to go first, because it may need the AST information
Expand Down Expand Up @@ -1027,10 +1002,10 @@ namespace cling {
bool DeclUnloader::VisitFunctionTemplateDecl(FunctionTemplateDecl* FTD) {
bool Successful = true;

// Remove specializations:
// Remove specializations, but do not invalidate the iterator!
for (FunctionTemplateDecl::spec_iterator I = FTD->loaded_spec_begin(),
E = FTD->loaded_spec_end(); I != E; ++I)
Successful &= Visit(*I);
Successful &= VisitFunctionDecl(*I, /*RemoveSpec=*/false);

Successful &= VisitRedeclarableTemplateDecl(FTD);
Successful &= VisitFunctionDecl(FTD->getTemplatedDecl());
Expand All @@ -1040,29 +1015,74 @@ namespace cling {
bool DeclUnloader::VisitClassTemplateDecl(ClassTemplateDecl* CTD) {
// ClassTemplateDecl: TemplateDecl, Redeclarable
bool Successful = true;
// Remove specializations:
// Remove specializations, but do not invalidate the iterator!
for (ClassTemplateDecl::spec_iterator I = CTD->loaded_spec_begin(),
E = CTD->loaded_spec_end(); I != E; ++I)
Successful &= Visit(*I);
Successful &=
VisitClassTemplateSpecializationDecl(*I, /*RemoveSpec=*/false);

Successful &= VisitRedeclarableTemplateDecl(CTD);
Successful &= Visit(CTD->getTemplatedDecl());
return Successful;
}

bool DeclUnloader::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl* CTSD) {
ClassTemplateSpecializationDecl* CTSD, bool RemoveSpec) {
// ClassTemplateSpecializationDecl: CXXRecordDecl, FoldingSet
bool Successful = VisitCXXRecordDecl(CTSD);
ClassTemplateSpecializationDecl* CanonCTSD =
static_cast<ClassTemplateSpecializationDecl*>(CTSD->getCanonicalDecl());
if (auto D = dyn_cast<ClassTemplatePartialSpecializationDecl>(CanonCTSD))
ClassTemplateDeclExt::removePartialSpecialization(
D->getSpecializedTemplate(),
D);
else
ClassTemplateDeclExt::removeSpecialization(CTSD->getSpecializedTemplate(),
CanonCTSD);
if (RemoveSpec) {
ClassTemplateSpecializationDecl* CanonCTSD =
static_cast<ClassTemplateSpecializationDecl*>(
CTSD->getCanonicalDecl());
if (auto D = dyn_cast<ClassTemplatePartialSpecializationDecl>(CanonCTSD))
ClassTemplateDeclExt::removePartialSpecialization(
D->getSpecializedTemplate(), D);
else
ClassTemplateDeclExt::removeSpecialization(
CTSD->getSpecializedTemplate(), CanonCTSD);
}
return Successful;
}

bool DeclUnloader::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl* CTSD) {
return VisitClassTemplateSpecializationDecl(CTSD, /*RemoveSpec=*/true);
}

bool DeclUnloader::VisitVarTemplateDecl(VarTemplateDecl* VTD) {
// VarTemplateDecl: TemplateDecl, Redeclarable
bool Successful = true;
// Remove specializations, but do not invalidate the iterator!
for (VarTemplateDecl::spec_iterator I = VTD->loaded_spec_begin(),
E = VTD->loaded_spec_end();
I != E; ++I)
Successful &=
VisitVarTemplateSpecializationDecl(*I, /*RemoveSpec=*/false);

Successful &= VisitRedeclarableTemplateDecl(VTD);
Successful &= Visit(VTD->getTemplatedDecl());
return Successful;
}

bool DeclUnloader::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl* VTSD, bool RemoveSpec) {
// VarTemplateSpecializationDecl: VarDecl, FoldingSet
bool Successful = VisitVarDecl(VTSD);
if (RemoveSpec) {
VarTemplateSpecializationDecl* CanonVTSD =
static_cast<VarTemplateSpecializationDecl*>(VTSD->getCanonicalDecl());
if (auto D = dyn_cast<VarTemplatePartialSpecializationDecl>(CanonVTSD))
VarTemplateDeclExt::removePartialSpecialization(
D->getSpecializedTemplate(), D);
else
VarTemplateDeclExt::removeSpecialization(VTSD->getSpecializedTemplate(),
CanonVTSD);
}
return Successful;
}

bool DeclUnloader::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl* VTSD) {
return VisitVarTemplateSpecializationDecl(VTSD, /*RemoveSpec=*/true);
}
} // end namespace cling
51 changes: 50 additions & 1 deletion interpreter/cling/lib/Interpreter/DeclUnloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ namespace cling {
///
bool VisitVarDecl(clang::VarDecl* VD);

///\brief Removes the declaration from the lookup chains and from the
/// declaration context and it rebuilds the redeclaration chain.
/// @param[in] FD - The declaration to be removed.
/// @param[in] RemoveSpec - If a template specialization, whether to remove
/// it from the parent.
///
///\returns true on success.
///
bool VisitFunctionDecl(clang::FunctionDecl* FD, bool RemoveSpec);

///\brief Removes the declaration from the lookup chains and from the
/// declaration context and it rebuilds the redeclaration chain.
/// @param[in] FD - The declaration to be removed.
Expand Down Expand Up @@ -228,14 +238,53 @@ namespace cling {
///
bool VisitClassTemplateDecl(clang::ClassTemplateDecl* CTD);

///\brief Removes a class template specialization declaration from clang's
/// internal structures.
/// @param[in] CTSD - The declaration to be removed.
/// @param[in] RemoveSpec - Whether to remove the specialization from its
/// parent.
///
///\returns true on success.
///
bool VisitClassTemplateSpecializationDecl(
clang::ClassTemplateSpecializationDecl* CTSD, bool RemoveSpec);

///\brief Removes a class template specialization declaration from clang's
/// internal structures.
/// @param[in] CTSD - The declaration to be removed.
///
///\returns true on success.
///
bool VisitClassTemplateSpecializationDecl(
clang::ClassTemplateSpecializationDecl* CTSD);
clang::ClassTemplateSpecializationDecl* CTSD);

///\brief Removes a var template declaration from clang's internal
/// structures.
/// @param[in] VTD - The declaration to be removed.
///
///\returns true on success.
///
bool VisitVarTemplateDecl(clang::VarTemplateDecl* VTD);

///\brief Removes a var template specialization declaration from clang's
/// internal structures.
/// @param[in] CTSD - The declaration to be removed.
/// @param[in] RemoveSpec - Whether to remove the specialization from its
/// parent.
///
///\returns true on success.
///
bool VisitVarTemplateSpecializationDecl(
clang::VarTemplateSpecializationDecl* VTSD, bool RemoveSpec);

///\brief Removes a var template specialization declaration from clang's
/// internal structures.
/// @param[in] CTSD - The declaration to be removed.
///
///\returns true on success.
///
bool VisitVarTemplateSpecializationDecl(
clang::VarTemplateSpecializationDecl* VTSD);

///@}

Expand Down
Loading