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
10 changes: 9 additions & 1 deletion interpreter/cling/lib/Interpreter/DeclUnloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,15 @@ namespace cling {
Successful &=
VisitClassTemplateSpecializationDecl(*I, /*RemoveSpec=*/false);

Successful &= VisitRedeclarableTemplateDecl(CTD);
// Visit all redeclarations of this template to ensure the full
// redecl chain is unloaded properly.
// Not doing this will lead to a corrupted decl chain and can cause
// assertions later down the line.
// We also need to make a copy of `CTD->redecls()` to not mess up the chain
llvm::SmallVector<RedeclarableTemplateDecl*> redecls(CTD->redecls());
for (auto* Redecl : redecls)
Successful &= VisitRedeclarableTemplateDecl(Redecl);

Successful &= Visit(CTD->getTemplatedDecl());
return Successful;
}
Expand Down
12 changes: 12 additions & 0 deletions roottest/root/meta/redeclUnload/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)

ROOTTEST_GENERATE_REFLEX_DICTIONARY(TemplateRedecl
inc/RedeclTrigger.h
SELECTION inc/redecl_selection.xml
FIXTURES_SETUP root-meta-redeclUnload-TemplateRedecl-fixture)

ROOTTEST_ADD_TEST(templateRedeclUnload
MACRO testTemplateRedeclUnload.C
ROOTEXE_OPTS -e "gInterpreter->AddIncludePath(\"-I${CMAKE_CURRENT_SOURCE_DIR}\")"
OUTREF TemplateRedeclUnload.ref
FIXTURES_REQUIRED root-meta-redeclUnload-TemplateRedecl-fixture)
1 change: 1 addition & 0 deletions roottest/root/meta/redeclUnload/TemplateRedeclUnload.ref
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

8 changes: 8 additions & 0 deletions roottest/root/meta/redeclUnload/inc/RedeclTrigger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Two wrappers are needed to reproduce the assertion with broken redecl chain.
template <typename T>
class Wrapper1 {};
template <typename T>
class Wrapper2 {};

class RandomClass {};
Wrapper1<Wrapper2<RandomClass>> var;
4 changes: 4 additions & 0 deletions roottest/root/meta/redeclUnload/inc/redecl_selection.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<lcgdict>
<class name="RandomClass" splitLevel="0"/>
<class name="Wrapper1<Wrapper2<RandomClass>>" splitLevel="0"/>
</lcgdict>
12 changes: 12 additions & 0 deletions roottest/root/meta/redeclUnload/testTemplateRedeclUnload.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
void testTemplateRedeclUnload()
{
gROOT->ProcessLine("gSystem->Load(\"libTemplateRedecl_dictrflx\");");
gROOT->ProcessLine("gInterpreter->AutoParse(\"RandomClass\");");

// Undo the last 2 commands, which unloads the templates.
gROOT->ProcessLine(".undo 2");

// Before the fix: cling crashes here with:
// "Passed first decl twice, invalid redecl chain!"
gROOT->ProcessLine("RandomClass obj;");
}
Loading